封装中间件
This commit is contained in:
@@ -1,55 +0,0 @@
|
|||||||
package loggerx
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
uuid "github.com/satori/go.uuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 可以被引入的中间件
|
|
||||||
|
|
||||||
// 自动设置请求ID
|
|
||||||
func SetTraceId(ctx context.Context) context.Context {
|
|
||||||
return context.WithValue(ctx, "trace_id", uuid.NewV4().String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// 中间件 gin框架保存请求相关信息
|
|
||||||
func MiddlewareGetGinParams(log *Logger) gin.HandlerFunc {
|
|
||||||
return func(ctx *gin.Context) {
|
|
||||||
// 使用bytes.Buffer来读取并记录请求体,同时避免改变ctx.Request.Body
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
tea := io.TeeReader(ctx.Request.Body, buf)
|
|
||||||
|
|
||||||
// 读取body
|
|
||||||
body, err := io.ReadAll(tea)
|
|
||||||
if err != nil {
|
|
||||||
log.Infof(ctx, "Error reading request body: %v", err)
|
|
||||||
ctx.AbortWithStatus(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 截取body的前1000个字符
|
|
||||||
bodyStr := string(body)
|
|
||||||
if len(bodyStr) > 1000 {
|
|
||||||
bodyStr = bodyStr[:1000]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用NopCloser包裹buffer,仅为了确保在读取body之后body可以被关闭,但并不改变原始的Request.Body
|
|
||||||
ctx.Request.Body = io.NopCloser(buf)
|
|
||||||
|
|
||||||
m := map[string]interface{}{
|
|
||||||
"method": ctx.Request.Method,
|
|
||||||
"uri": ctx.Request.RequestURI,
|
|
||||||
"body": bodyStr,
|
|
||||||
"query": ctx.Request.URL.Query(),
|
|
||||||
"header": ctx.Request.Header,
|
|
||||||
}
|
|
||||||
log.Infof(ctx, "request %+v", m)
|
|
||||||
ctx.Next()
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/yuninks/loggerx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 可以被引入的中间件
|
||||||
|
|
||||||
|
// 自动设置请求ID
|
||||||
|
|
||||||
|
// 中间件 gin框架保存请求响应相关信息
|
||||||
|
func SetGinParams(log *loggerx.Logger) gin.HandlerFunc {
|
||||||
|
return func(ctx *gin.Context) {
|
||||||
|
|
||||||
|
// 使用bytes.Buffer来读取并记录请求体,同时避免改变ctx.Request.Body
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
tea := io.TeeReader(ctx.Request.Body, buf)
|
||||||
|
|
||||||
|
// 读取body
|
||||||
|
body, err := io.ReadAll(tea)
|
||||||
|
if err != nil {
|
||||||
|
log.Infof(ctx, "Error reading request body: %v", err)
|
||||||
|
ctx.AbortWithStatus(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 截取body的前1000个字符
|
||||||
|
bodyStr := string(body)
|
||||||
|
if len(bodyStr) > 1000 {
|
||||||
|
bodyStr = bodyStr[:1000]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用NopCloser包裹buffer,仅为了确保在读取body之后body可以被关闭,但并不改变原始的Request.Body
|
||||||
|
ctx.Request.Body = io.NopCloser(buf)
|
||||||
|
|
||||||
|
// 下面是响应参数缓存
|
||||||
|
blw := &bodyParamsWriter{
|
||||||
|
body: bytes.NewBufferString(""),
|
||||||
|
ResponseWriter: ctx.Writer,
|
||||||
|
}
|
||||||
|
ctx.Writer = blw
|
||||||
|
|
||||||
|
req := struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
ClientIP string `json:"client_ip"`
|
||||||
|
Body string `json:"body"`
|
||||||
|
Header map[string][]string `json:"header"`
|
||||||
|
}{
|
||||||
|
Method: ctx.Request.Method,
|
||||||
|
Path: ctx.FullPath(),
|
||||||
|
ClientIP: ctx.ClientIP(),
|
||||||
|
Body: bodyStr,
|
||||||
|
Header: ctx.Request.Header,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info(ctx, "request", req)
|
||||||
|
|
||||||
|
ctx.Next()
|
||||||
|
|
||||||
|
// 判断返回的值是否json
|
||||||
|
contentType := ctx.Writer.Header().Get("Content-Type")
|
||||||
|
|
||||||
|
if !strings.Contains(contentType, "application/json") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
respData := blw.body.String()
|
||||||
|
|
||||||
|
resp := struct {
|
||||||
|
HttpCode int `json:"http_code"`
|
||||||
|
Response string `json:"response"`
|
||||||
|
}{
|
||||||
|
HttpCode: ctx.Writer.Status(),
|
||||||
|
Response: respData,
|
||||||
|
// Header: ctx.Writer.Header(),
|
||||||
|
}
|
||||||
|
log.Info(ctx, "response", resp)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type bodyParamsWriter struct {
|
||||||
|
gin.ResponseWriter
|
||||||
|
body *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// 真正输出的时候,它会调用这个输出方法
|
||||||
|
func (w bodyParamsWriter) Write(b []byte) (int, error) {
|
||||||
|
// b = []byte(`{"code":0}`)
|
||||||
|
w.body.Write(b)
|
||||||
|
return w.ResponseWriter.Write(b)
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
uuid "github.com/satori/go.uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 设置普通的traceId
|
||||||
|
func SetTraceId(ctx context.Context, traceKey string) context.Context {
|
||||||
|
if traceKey == "" {
|
||||||
|
traceKey = "trace_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
val := ctx.Value(traceKey)
|
||||||
|
if val == nil {
|
||||||
|
ctx = context.WithValue(ctx, traceKey, uuid.NewV4().String())
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置Gin的traceId
|
||||||
|
func SetGinTraceId(traceKey string) gin.HandlerFunc {
|
||||||
|
|
||||||
|
if traceKey == "" {
|
||||||
|
traceKey = "trace_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(ctx *gin.Context) {
|
||||||
|
traceId := ctx.Request.Header.Get(traceKey)
|
||||||
|
if traceId == "" {
|
||||||
|
traceId = uuid.NewV4().String()
|
||||||
|
}
|
||||||
|
ctx.Set(traceKey, traceId)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user