微信小程序\推拉流
This commit is contained in:
@@ -8,6 +8,7 @@ package middleware
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -18,6 +19,90 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 二进制 Content-Type 前缀列表
|
||||
var binaryContentTypes = []string{
|
||||
"image/",
|
||||
"audio/",
|
||||
"video/",
|
||||
"application/octet-stream",
|
||||
"application/pdf",
|
||||
"application/zip",
|
||||
"application/x-rar",
|
||||
"application/x-7z",
|
||||
"application/gzip",
|
||||
"application/x-tar",
|
||||
"font/",
|
||||
}
|
||||
|
||||
// 不需要记录响应体的路由前缀
|
||||
var skipResponseBodyRoutes = []string{
|
||||
"/uploads/",
|
||||
"/static/",
|
||||
}
|
||||
|
||||
// isBinaryContentType 检测是否为二进制 Content-Type
|
||||
func isBinaryContentType(contentType string) bool {
|
||||
contentType = strings.ToLower(contentType)
|
||||
for _, prefix := range binaryContentTypes {
|
||||
if strings.HasPrefix(contentType, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isBinaryData 检测数据是否为二进制(通过检查是否包含非 UTF-8 字符)
|
||||
func isBinaryData(data []byte) bool {
|
||||
if len(data) == 0 {
|
||||
return false
|
||||
}
|
||||
// 检查前 512 字节是否包含二进制特征
|
||||
checkLen := len(data)
|
||||
if checkLen > 512 {
|
||||
checkLen = 512
|
||||
}
|
||||
for i := 0; i < checkLen; i++ {
|
||||
// 检测常见的二进制文件头
|
||||
if data[i] == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// 检查是否以常见的二进制文件头开始
|
||||
if len(data) >= 2 {
|
||||
// JPEG: FF D8
|
||||
if data[0] == 0xFF && data[1] == 0xD8 {
|
||||
return true
|
||||
}
|
||||
// PNG: 89 50
|
||||
if data[0] == 0x89 && data[1] == 0x50 {
|
||||
return true
|
||||
}
|
||||
// GIF: 47 49
|
||||
if data[0] == 0x47 && data[1] == 0x49 {
|
||||
return true
|
||||
}
|
||||
// PDF: 25 50
|
||||
if data[0] == 0x25 && data[1] == 0x50 {
|
||||
return true
|
||||
}
|
||||
// ZIP/DOCX/XLSX: 50 4B
|
||||
if data[0] == 0x50 && data[1] == 0x4B {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// shouldSkipResponseBody 检测是否应该跳过响应体记录
|
||||
func shouldSkipResponseBody(path string) bool {
|
||||
for _, prefix := range skipResponseBodyRoutes {
|
||||
if strings.HasPrefix(path, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RequestLogMiddleware 请求日志中间件
|
||||
type RequestLogMiddleware struct {
|
||||
DB *gorm.DB
|
||||
@@ -39,7 +124,7 @@ func (m *RequestLogMiddleware) Handler() gin.HandlerFunc {
|
||||
|
||||
// 获取请求IP
|
||||
ip := getClientIP(c)
|
||||
|
||||
|
||||
// 本地IP不记录
|
||||
if utils.GetIPLocation(ip) == "本地" {
|
||||
c.Next()
|
||||
@@ -67,7 +152,7 @@ func (m *RequestLogMiddleware) Handler() gin.HandlerFunc {
|
||||
// 创建响应写入器
|
||||
writer := &responseWriter{
|
||||
ResponseWriter: c.Writer,
|
||||
body: &bytes.Buffer{},
|
||||
body: &bytes.Buffer{},
|
||||
}
|
||||
c.Writer = writer
|
||||
|
||||
@@ -89,24 +174,43 @@ func (m *RequestLogMiddleware) logRequest(c *gin.Context, ip, userID string, req
|
||||
|
||||
// 获取响应code(从响应体中解析)
|
||||
responseCode := 0
|
||||
if len(responseBody) > 0 {
|
||||
// 尝试解析响应体获取code
|
||||
if len(responseBody) > 0 && !isBinaryData(responseBody) {
|
||||
// 尝试解析响应体获取code(仅对非二进制数据)
|
||||
var resp model.ApiResponse
|
||||
if err := json.Unmarshal(responseBody, &resp); err == nil {
|
||||
responseCode = resp.Code
|
||||
}
|
||||
}
|
||||
|
||||
// 限制请求参数长度(避免存储过大)
|
||||
requestParams := string(requestBody)
|
||||
if len(requestParams) > 5000 {
|
||||
requestParams = requestParams[:5000] + "...(truncated)"
|
||||
// 处理请求参数
|
||||
var requestParams string
|
||||
requestContentType := c.GetHeader("Content-Type")
|
||||
if isBinaryContentType(requestContentType) || isBinaryData(requestBody) {
|
||||
// 二进制请求体,只记录大小
|
||||
requestParams = fmt.Sprintf("[binary data: %d bytes]", len(requestBody))
|
||||
} else {
|
||||
requestParams = string(requestBody)
|
||||
if len(requestParams) > 5000 {
|
||||
requestParams = requestParams[:5000] + "...(truncated)"
|
||||
}
|
||||
}
|
||||
|
||||
// 限制返回参数长度
|
||||
responseParams := string(responseBody)
|
||||
if len(responseParams) > 5000 {
|
||||
responseParams = responseParams[:5000] + "...(truncated)"
|
||||
// 处理响应参数
|
||||
var responseParams string
|
||||
responseContentType := c.Writer.Header().Get("Content-Type")
|
||||
requestPath := c.Request.URL.Path
|
||||
|
||||
if shouldSkipResponseBody(requestPath) {
|
||||
// 静态文件路由,跳过响应体记录
|
||||
responseParams = fmt.Sprintf("[static file: %d bytes]", len(responseBody))
|
||||
} else if isBinaryContentType(responseContentType) || isBinaryData(responseBody) {
|
||||
// 二进制响应体,只记录大小
|
||||
responseParams = fmt.Sprintf("[binary data: %d bytes]", len(responseBody))
|
||||
} else {
|
||||
responseParams = string(responseBody)
|
||||
if len(responseParams) > 5000 {
|
||||
responseParams = responseParams[:5000] + "...(truncated)"
|
||||
}
|
||||
}
|
||||
|
||||
// 创建日志记录
|
||||
@@ -170,4 +274,3 @@ func (w *responseWriter) WriteHeader(statusCode int) {
|
||||
w.status = statusCode
|
||||
w.ResponseWriter.WriteHeader(statusCode)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user