中间件
响应中间件、CORS 跨域处理与 Option 请求
中间件
Bamboo Base 提供常用的中间件,用于处理跨域、统一响应等场景。
ResponseMiddleware - 统一响应中间件
自动包装响应为统一格式:
func ResponseMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 包装 ResponseWriter
blw := &bodyLogWriter{
body: bytes.NewBufferString(""),
ResponseWriter: c.Writer,
}
c.Writer = blw
c.Next()
// 如果已经有响应内容,跳过
if blw.body.Len() > 0 {
return
}
// 处理错误
if len(c.Errors) > 0 {
err := c.Errors.Last().Err
c.JSON(200, BaseResponse{
Code: getErrorCode(err),
Message: err.Error(),
Timestamp: time.Now().UnixMilli(),
})
return
}
// 默认成功响应
c.JSON(200, BaseResponse{
Code: 200,
Message: "success",
Timestamp: time.Now().UnixMilli(),
})
}
}使用方式
func main() {
r := gin.New()
// 注册响应中间件
r.Use(middleware.ResponseMiddleware())
r.GET("/api/data", func(c *gin.Context) {
// 直接返回数据,中间件自动包装
c.Set("response", data)
})
}CORS 跨域处理
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
origin := c.Request.Header.Get("Origin")
// 允许的域名
allowedOrigins := []string{
"http://localhost:3000",
"https://example.com",
}
// 检查是否允许
for _, allowed := range allowedOrigins {
if origin == allowed {
c.Header("Access-Control-Allow-Origin", origin)
break
}
}
// 允许的请求头
c.Header("Access-Control-Allow-Headers",
"Content-Type, Authorization, X-Requested-With")
// 允许的方法
c.Header("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS")
// 允许携带 Cookie
c.Header("Access-Control-Allow-Credentials", "true")
// 预检请求缓存时间
c.Header("Access-Control-Max-Age", "86400")
c.Next()
}
}配置示例
func main() {
r := gin.Default()
// 注册 CORS 中间件
r.Use(middleware.CORSMiddleware())
// 路由...
}Option 请求处理
自动处理 OPTIONS 预检请求:
func OptionsMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}日志中间件
记录请求日志:
func LoggerMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
path := c.Request.URL.Path
c.Next()
latency := time.Since(start)
status := c.Writer.Status()
web.Register.Logger.Info("request",
"method", c.Request.Method,
"path", path,
"status", status,
"latency", latency,
"ip", c.ClientIP(),
)
}
}恢复中间件
捕获 panic 防止服务崩溃:
func RecoveryMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
defer func() {
if err := recover(); err != nil {
web.Register.Logger.Error("panic recovered",
"error", err,
"stack", debug.Stack(),
)
c.JSON(500, BaseResponse{
Code: 500001,
Message: "系统内部错误",
})
c.Abort()
}
}()
c.Next()
}
}中间件组合使用
func main() {
r := gin.New()
// 按顺序注册中间件
r.Use(middleware.RecoveryMiddleware()) // 1. 恢复
r.Use(middleware.LoggerMiddleware()) // 2. 日志
r.Use(middleware.CORSMiddleware()) // 3. 跨域
r.Use(middleware.OptionsMiddleware()) // 4. OPTIONS
r.Use(middleware.ResponseMiddleware()) // 5. 响应包装
// 路由...
}自定义中间件
认证中间件
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.JSON(401, BaseResponse{
Code: 110001,
Message: "未授权",
})
c.Abort()
return
}
// 验证 token...
userID, err := validateToken(token)
if err != nil {
c.JSON(401, BaseResponse{
Code: 110002,
Message: "Token 无效",
})
c.Abort()
return
}
// 将用户信息存入上下文
c.Set("userID", userID)
c.Next()
}
}限流中间件
func RateLimitMiddleware(maxRequests int, window time.Duration) gin.HandlerFunc {
limiter := rate.NewLimiter(rate.Every(window/time.Duration(maxRequests)), maxRequests)
return func(c *gin.Context) {
if !limiter.Allow() {
c.JSON(429, BaseResponse{
Code: 000004,
Message: "请求过于频繁",
})
c.Abort()
return
}
c.Next()
}
}路由组中间件
func main() {
r := gin.Default()
// 公开路由(无需认证)
public := r.Group("/api/public")
{
public.GET("/login", loginHandler)
public.POST("/register", registerHandler)
}
// 私有路由(需要认证)
private := r.Group("/api/private")
private.Use(middleware.AuthMiddleware())
{
private.GET("/profile", profileHandler)
private.POST("/settings", settingsHandler)
}
}