Files
web_template/internal/middleware/access_log.go
2026-09-09 02:39:57 +08:00

79 lines
1.6 KiB
Go

package middleware
import (
"net/http"
"strings"
"time"
"gotest/internal/geoip"
"gotest/internal/model"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// responseWriter 包装 gin.ResponseWriter 以捕获状态码
type responseWriter struct {
gin.ResponseWriter
statusCode int
}
func (w *responseWriter) WriteHeader(code int) {
w.statusCode = code
w.ResponseWriter.WriteHeader(code)
}
// AccessLog 访问日志中间件,记录每次 HTTP 请求到数据库
func AccessLog(db *gorm.DB, ipService *geoip.Service) gin.HandlerFunc {
return func(c *gin.Context) {
// 跳过健康检查和静态资源
path := c.Request.URL.Path
if path == "/api/health" || strings.HasPrefix(path, "/shared/") || strings.HasPrefix(path, "/assets/") {
c.Next()
return
}
start := time.Now()
clientIP := c.ClientIP()
// 包装响应写入器以捕获状态码
rw := &responseWriter{ResponseWriter: c.Writer, statusCode: http.StatusOK}
c.Writer = rw
c.Next()
// 异步写入日志(不阻塞请求响应)
go func() {
cost := int(time.Since(start).Milliseconds())
ua := c.Request.UserAgent()
if len(ua) > 500 {
ua = ua[:500]
}
referer := c.Request.Referer()
if len(referer) > 500 {
referer = referer[:500]
}
p := c.Request.URL.Path
if len(p) > 500 {
p = p[:500]
}
// 查询 IP 归属地
location := ipService.Lookup(clientIP)
log := model.AccessLog{
IP: clientIP,
Path: p,
Method: c.Request.Method,
UserAgent: ua,
Referer: referer,
Location: location,
Status: rw.statusCode,
Cost: cost,
}
db.Create(&log)
}()
}
}