middleHandle.go 3.74 KB
Newer Older
chenweijian's avatar
chenweijian committed
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 130
package route

import (
	"bytes"
	"github.com/gin-gonic/gin"
	"hilo-user/_const"
	"hilo-user/mycontext"
	"hilo-user/myerr/bizerr"
	"hilo-user/mylogrus"
	"hilo-user/req"
	"hilo-user/req/jwt"
	"hilo-user/resource/config"
	"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(_const.USERID, claims.UserId)
	c.Set(_const.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()
	reqUri := c.Request.RequestURI
	c.Set(_const.TRACEID, traceId)
	//
	header := c.Request.Header
	//类型
	devicetype := header.Get("Devicetype")
	c.Set(_const.DEVICETYPE, devicetype)
	appVersion := header.Get("Appversion")
	c.Set(_const.APP_VERSION, appVersion)
	c.Set(_const.URL, reqUri)
	c.Set(_const.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)
}