1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package route
import (
"bytes"
"git.hilo.cn/hilo-common/mycontext"
"git.hilo.cn/hilo-common/mylogrus"
"git.hilo.cn/hilo-common/resource/config"
"github.com/gin-gonic/gin"
"hilo-user/myerr/bizerr"
"hilo-user/req"
"hilo-user/req/jwt"
"hilo-user/resp"
"io/ioutil"
"runtime/debug"
"strings"
"time"
)
/**
controller层全局异常处理
*/
// 等级最高,为了只为最后有返回值到前端
func ExceptionHandle(c *gin.Context) {
defer func() {
if r := recover(); r != nil {
//打印错误堆栈信息
mylogrus.MyLog.Errorf("ExceptionHandle SYSTEM ACTION PANIC: %v, stack: %v", r, string(debug.Stack()))
resp.ResponseErrWithString(c, r)
//终止后续接口调用,不加的话recover到异常后,还会继续执行接口里后续代码
c.Abort()
}
}()
c.Next()
}
// jwt解密
func JWTApiHandle(c *gin.Context) {
logger := mylogrus.MyLog.WithField("URL", c.Request.URL).WithField("METHOD", c.Request.Method)
token := c.GetHeader("token")
if token == "" {
logger.Warnf("token err is empty! %v", c.Request.Header)
resp.ResponseBusiness(c, bizerr.TokenInvalid)
c.Abort()
return
}
claims, err := jwt.ParseToken(token)
if err != nil {
logger.Warnf("token parsed err:%v", err)
resp.ResponseBusiness(c, bizerr.TokenInvalid)
c.Abort()
return
}
logger = logger.WithField("userId", claims.UserId)
if time.Now().Unix() > claims.ExpiresAt {
logger.Warnf("token expire err, now: %d, expiresAt %d", time.Now().Unix(), claims.ExpiresAt)
resp.ResponseBusiness(c, bizerr.TokenInvalid)
c.Abort()
return
}
if claims.Issuer != config.GetConfigJWT().ISSUER_API {
logger.Warnf("token err issuer:%s, configIssuer %s", claims.Issuer, config.GetConfigJWT().ISSUER_API)
resp.ResponseBusiness(c, bizerr.TokenInvalid)
c.Abort()
return
}
var newToken = token
// token 连续7天没玩,第八天回来后给新token(线上是30天过期)
if claims.ExpiresAt-time.Now().Unix() < 86400*7 {
logger.Infof("token nearly expire err, now:%d,expiresAt:%d", time.Now().Unix(), claims.ExpiresAt)
newToken, err = jwt.GenerateToken(claims.UserId, claims.ExternalId, config.GetConfigJWT().ISSUER_API)
if err != nil {
logger.Warnf("token generation failed, err:%v", err)
resp.ResponseBusiness(c, bizerr.TokenInvalid)
c.Abort()
return
}
}
c.Set(mycontext.USERID, claims.UserId)
c.Set(mycontext.EXTERNAL_ID, claims.ExternalId)
c.Writer.Header().Add("token", newToken)
c.Next()
}
// 日志Handle
func LoggerHandle(c *gin.Context) {
//开始时间
start := time.Now()
clientIp := c.ClientIP()
method := c.Request.Method
traceId := genTraceId(c)
reqUri := c.Request.RequestURI
c.Set(mycontext.TRACEID, traceId)
//
header := c.Request.Header
//类型
devicetype := header.Get("Devicetype")
c.Set(mycontext.DEVICETYPE, devicetype)
appVersion := header.Get("Appversion")
c.Set(mycontext.APP_VERSION, appVersion)
c.Set(mycontext.URL, reqUri)
c.Set(mycontext.METHOD, method)
userId, _ := req.GetUserId(c)
bodyStr := ""
contentType := c.Request.Header.Get("Content-Type")
//文件就不打印
if strings.Index(contentType, "multipart/form-data") == -1 {
data, err := c.GetRawData()
if err != nil {
mylogrus.MyLog.Errorf("handle log err:%v", err)
}
bodyStr = string(data)
//很关键
//把读过的字节流重新放到body
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data))
}
mycontext.CreateMyContext(c.Keys).Log.Infof("request start traceId:%v, clientIp:%v, url:%v, method:%v, userId:%v, body:%v, header:%v", traceId, clientIp, reqUri, method, userId, bodyStr, header)
//加载完 defer recover,继续后续接口调用
c.Next()
end := time.Now()
latency := end.Sub(start)
mycontext.CreateMyContext(c.Keys).Log.Infof("request end fullPath:%v,url:%v, method: %v, traceId:%v, latency:%v userId:%v", c.FullPath(), reqUri, method, traceId, latency, userId)
}