Files
atom/middleware/operation.go
2023-01-31 16:07:29 +08:00

132 lines
3.4 KiB
Go

package middleware
import (
"atom/database/models"
"atom/providers/jwt"
"atom/providers/log"
"bytes"
"encoding/json"
"io"
"net/http"
"net/url"
"strconv"
"strings"
"sync"
"time"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
var respPool sync.Pool
func init() {
respPool.New = func() interface{} {
return make([]byte, 1024)
}
}
func OperationRecord(jwt *jwt.JWT) gin.HandlerFunc {
return func(c *gin.Context) {
var body []byte
var userId int64
if c.Request.Method != http.MethodGet {
var err error
body, err = io.ReadAll(c.Request.Body)
if err != nil {
log.Error("read body from request error:", zap.Error(err))
} else {
c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
}
} else {
query := c.Request.URL.RawQuery
query, _ = url.QueryUnescape(query)
split := strings.Split(query, "&")
m := make(map[string]string)
for _, v := range split {
kv := strings.Split(v, "=")
if len(kv) == 2 {
m[kv[0]] = kv[1]
}
}
body, _ = json.Marshal(&m)
}
claims, _ := jwt.GetClaims(c)
if claims.UserID != 0 {
userId = int64(claims.UserID)
} else {
id, err := strconv.Atoi(c.Request.Header.Get("x-user-id"))
if err != nil {
log.Error(err)
}
userId = int64(id)
}
record := models.SysOperationRecord{
IP: c.ClientIP(),
Method: c.Request.Method,
Path: c.Request.URL.Path,
Agent: c.Request.UserAgent(),
Body: string(body),
UserID: userId,
}
// 上传文件时候 中间件日志进行裁断操作
if strings.Contains(c.GetHeader("Content-Type"), "multipart/form-data") {
if len(record.Body) > 1024 {
// 截断
newBody := respPool.Get().([]byte)
copy(newBody, record.Body)
record.Body = string(newBody)
defer respPool.Put(&newBody)
}
}
writer := responseBodyWriter{
ResponseWriter: c.Writer,
body: &bytes.Buffer{},
}
c.Writer = writer
now := time.Now()
c.Next()
latency := time.Since(now)
record.ErrorMessage = c.Errors.ByType(gin.ErrorTypePrivate).String()
record.Status = int64(c.Writer.Status())
record.Latency = int64(latency)
record.Resp = writer.body.String()
if strings.Contains(c.Writer.Header().Get("Pragma"), "public") ||
strings.Contains(c.Writer.Header().Get("Expires"), "0") ||
strings.Contains(c.Writer.Header().Get("Cache-Control"), "must-revalidate, post-check=0, pre-check=0") ||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/force-download") ||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/octet-stream") ||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/vnd.ms-excel") ||
strings.Contains(c.Writer.Header().Get("Content-Type"), "application/download") ||
strings.Contains(c.Writer.Header().Get("Content-Disposition"), "attachment") ||
strings.Contains(c.Writer.Header().Get("Content-Transfer-Encoding"), "binary") {
if len(record.Resp) > 1024 {
// 截断
newBody := respPool.Get().([]byte)
copy(newBody, record.Resp)
record.Body = string(newBody)
defer respPool.Put(&newBody)
}
}
// if err := operationRecordService.CreateSysOperationRecord(record); err != nil {
// log.Error("create operation record error:", zap.Error(err))
// }
}
}
type responseBodyWriter struct {
gin.ResponseWriter
body *bytes.Buffer
}
func (r responseBodyWriter) Write(b []byte) (int, error) {
r.body.Write(b)
return r.ResponseWriter.Write(b)
}