常用中间件 #
一、内置中间件 #
1.1 Logger #
go
func main() {
r := gin.New()
// 默认Logger
r.Use(gin.Logger())
// 自定义格式
r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
return fmt.Sprintf("[GIN] %s | %s | %d | %v | %s | %s\n",
param.TimeStamp.Format("2006/01/02 - 15:04:05"),
param.ClientIP,
param.StatusCode,
param.Latency,
param.Method,
param.Path,
)
}))
// 写入文件
file, _ := os.Create("gin.log")
r.Use(gin.LoggerWithWriter(file))
// 跳过某些路径
r.Use(gin.LoggerWithConfig(gin.LoggerConfig{
SkipPaths: []string{"/health", "/metrics"},
}))
r.Run()
}
1.2 Recovery #
go
func main() {
r := gin.New()
// 默认Recovery
r.Use(gin.Recovery())
// 自定义Recovery
r.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) {
log.Printf("Panic recovered: %v", recovered)
c.AbortWithStatusJSON(500, gin.H{
"code": 500,
"message": "服务器内部错误",
})
}))
r.GET("/panic", func(c *gin.Context) {
panic("Something went wrong!")
})
r.Run()
}
1.3 Static #
go
func main() {
r := gin.New()
// 静态文件服务
r.Static("/assets", "./assets")
// 静态文件服务(带前缀)
r.StaticFS("/static", http.Dir("./static"))
// 单个文件
r.StaticFile("/favicon.ico", "./favicon.ico")
r.Run()
}
二、CORS中间件 #
2.1 基本用法 #
go
func main() {
r := gin.New()
// 简单CORS
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:3000"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowHeaders: []string{"Content-Type", "Authorization"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
r.Run()
}
2.2 配置选项 #
go
config := cors.Config{
// 允许的域名
AllowOrigins: []string{
"http://localhost:3000",
"https://example.com",
},
// 或使用通配符
AllowAllOrigins: true,
// 允许的方法
AllowMethods: []string{
"GET",
"POST",
"PUT",
"DELETE",
"OPTIONS",
},
// 允许的请求头
AllowHeaders: []string{
"Content-Type",
"Authorization",
"X-Requested-With",
},
// 暴露的响应头
ExposeHeaders: []string{
"Content-Length",
"X-Request-Id",
},
// 允许携带凭证
AllowCredentials: true,
// 预检请求缓存时间
MaxAge: 12 * time.Hour,
// 动态设置允许的域名
AllowOriginFunc: func(origin string) bool {
return strings.HasSuffix(origin, ".example.com")
},
}
r.Use(cors.New(config))
三、JWT中间件 #
3.1 安装 #
bash
go get github.com/appleboy/gin-jwt/v2
3.2 基本配置 #
go
package main
import (
"time"
jwt "github.com/appleboy/gin-jwt/v2"
"github.com/gin-gonic/gin"
)
type User struct {
ID string
Username string
Password string
}
var identityKey = "user_id"
func main() {
r := gin.New()
authMiddleware, err := jwt.New(&jwt.GinJWTMiddleware{
Realm: "test zone",
Key: []byte("secret key"),
Timeout: time.Hour,
MaxRefresh: time.Hour,
IdentityKey: identityKey,
PayloadFunc: func(data interface{}) jwt.MapClaims {
if v, ok := data.(*User); ok {
return jwt.MapClaims{
identityKey: v.ID,
}
}
return jwt.MapClaims{}
},
IdentityHandler: func(c *gin.Context) interface{} {
claims := jwt.ExtractClaims(c)
return &User{
ID: claims[identityKey].(string),
}
},
Authenticator: func(c *gin.Context) (interface{}, error) {
var loginVals struct {
Username string `form:"username" json:"username" binding:"required"`
Password string `form:"password" json:"password" binding:"required"`
}
if err := c.ShouldBind(&loginVals); err != nil {
return nil, jwt.ErrMissingLoginValues
}
userID := loginVals.Username
password := loginVals.Password
if userID == "admin" && password == "admin" {
return &User{
ID: userID,
Username: userID,
}, nil
}
return nil, jwt.ErrFailedAuthentication
},
Authorizator: func(data interface{}, c *gin.Context) bool {
if v, ok := data.(*User); ok && v.ID == "admin" {
return true
}
return false
},
Unauthorized: func(c *gin.Context, code int, message string) {
c.JSON(code, gin.H{
"code": code,
"message": message,
})
},
TokenLookup: "header: Authorization, query: token, cookie: jwt",
TokenHeadName: "Bearer",
TimeFunc: time.Now,
})
if err != nil {
log.Fatal("JWT Error:" + err.Error())
}
// 登录路由
r.POST("/login", authMiddleware.LoginHandler)
// 刷新Token
r.POST("/refresh", authMiddleware.RefreshHandler)
// 需要认证的路由
auth := r.Group("/auth")
auth.Use(authMiddleware.MiddlewareFunc())
{
auth.GET("/hello", func(c *gin.Context) {
claims := jwt.ExtractClaims(c)
c.JSON(200, gin.H{
"user_id": claims[identityKey],
})
})
}
r.Run()
}
四、限流中间件 #
4.1 基于令牌桶 #
go
import (
"golang.org/x/time/rate"
)
func RateLimitMiddleware(rps int) gin.HandlerFunc {
limiter := rate.NewLimiter(rate.Limit(rps), rps)
return func(c *gin.Context) {
if !limiter.Allow() {
c.AbortWithStatusJSON(429, gin.H{
"code": 429,
"message": "请求过于频繁",
})
return
}
c.Next()
}
}
func main() {
r := gin.New()
r.Use(RateLimitMiddleware(100))
r.Run()
}
4.2 基于IP限流 #
go
type IPRateLimiter struct {
ips map[string]*rate.Limiter
mu sync.RWMutex
r rate.Limit
b int
}
func NewIPRateLimiter(r rate.Limit, b int) *IPRateLimiter {
return &IPRateLimiter{
ips: make(map[string]*rate.Limiter),
r: r,
b: b,
}
}
func (l *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
l.mu.Lock()
defer l.mu.Unlock()
limiter, exists := l.ips[ip]
if !exists {
limiter = rate.NewLimiter(l.r, l.b)
l.ips[ip] = limiter
}
return limiter
}
func RateLimitByIP(rps int) gin.HandlerFunc {
limiter := NewIPRateLimiter(rate.Limit(rps), rps)
return func(c *gin.Context) {
ip := c.ClientIP()
if !limiter.GetLimiter(ip).Allow() {
c.AbortWithStatusJSON(429, gin.H{
"code": 429,
"message": "请求过于频繁",
})
return
}
c.Next()
}
}
4.3 使用第三方库 #
bash
go get github.com/ulule/limiter/v3
go
import (
"github.com/ulule/limiter/v3"
mgin "github.com/ulule/limiter/v3/drivers/middleware/gin"
"github.com/ulule/limiter/v3/drivers/store/memory"
)
func main() {
r := gin.New()
// 创建存储
store := memory.NewStore()
// 创建限流器
rate := limiter.Rate{
Period: 1 * time.Minute,
Limit: 100,
}
instance := limiter.New(store, rate, limiter.WithTrustForwardHeader(true))
// 创建中间件
middleware := mgin.NewMiddleware(instance)
r.Use(middleware)
r.Run()
}
五、压缩中间件 #
5.1 Gzip压缩 #
bash
go get github.com/gin-contrib/gzip
go
import "github.com/gin-contrib/gzip"
func main() {
r := gin.New()
// 默认压缩
r.Use(gzip.Gzip(gzip.DefaultCompression))
// 自定义压缩级别
r.Use(gzip.Gzip(gzip.BestCompression))
// 排除某些路径
r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedPaths([]string{"/api/"})))
// 排除某些扩展名
r.Use(gzip.Gzip(gzip.DefaultCompression, gzip.WithExcludedExtensions([]string{".pdf", ".mp4"})))
r.Run()
}
六、安全中间件 #
6.1 Secure #
bash
go get github.com/gin-contrib/secure
go
import "github.com/gin-contrib/secure"
func main() {
r := gin.New()
r.Use(secure.New(secure.Config{
SSLRedirect: true,
SSLHost: "example.com",
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
STSSeconds: 315360000,
STSIncludeSubdomains: true,
FrameDeny: true,
ContentTypeNosniff: true,
BrowserXssFilter: true,
ContentSecurityPolicy: "default-src 'self'",
}))
r.Run()
}
6.2 CSRF #
bash
go get github.com/utrack/gin-csrf
go
import csrf "github.com/utrack/gin-csrf"
func main() {
r := gin.New()
r.Use(csrf.Middleware(csrf.Options{
Secret: "secret123",
ErrorFunc: func(c *gin.Context) {
c.String(400, "CSRF token mismatch")
c.Abort()
},
}))
r.GET("/protected", func(c *gin.Context) {
c.String(200, csrf.GetToken(c))
})
r.POST("/protected", func(c *gin.Context) {
c.String(200, "OK")
})
r.Run()
}
七、监控中间件 #
7.1 Prometheus #
bash
go get github.com/gin-contrib/prometheus
go
import "github.com/gin-contrib/prometheus"
func main() {
r := gin.New()
p := prometheus.NewPrometheus("gin")
p.Use(r)
// 自定义指标
p.ReqCntURLLabelMappingFn = func(c *gin.Context) string {
return c.Request.URL.Path
}
r.GET("/metrics", func(c *gin.Context) {
prometheus.Handler().ServeHTTP(c.Writer, c.Request)
})
r.Run()
}
7.2 健康检查 #
go
func HealthCheck() gin.HandlerFunc {
return func(c *gin.Context) {
c.JSON(200, gin.H{
"status": "ok",
"time": time.Now().Format(time.RFC3339),
})
}
}
func ReadinessCheck(db *sql.DB) gin.HandlerFunc {
return func(c *gin.Context) {
if err := db.Ping(); err != nil {
c.JSON(503, gin.H{
"status": "not ready",
"error": err.Error(),
})
return
}
c.JSON(200, gin.H{
"status": "ready",
})
}
}
func main() {
r := gin.New()
r.GET("/health", HealthCheck())
r.GET("/ready", ReadinessCheck(db))
r.Run()
}
八、总结 #
8.1 常用中间件列表 #
| 中间件 | 用途 | 包名 |
|---|---|---|
| Logger | 日志记录 | gin内置 |
| Recovery | 错误恢复 | gin内置 |
| CORS | 跨域处理 | gin-contrib/cors |
| JWT | 身份认证 | appleboy/gin-jwt |
| Gzip | 响应压缩 | gin-contrib/gzip |
| Secure | 安全头 | gin-contrib/secure |
| CSRF | CSRF防护 | utrack/gin-csrf |
| Prometheus | 指标监控 | gin-contrib/prometheus |
8.2 最佳实践 #
| 实践 | 说明 |
|---|---|
| 按需引入 | 只使用必要的中间件 |
| 合理配置 | 根据环境调整配置 |
| 性能监控 | 关注中间件性能影响 |
| 错误处理 | 统一错误处理机制 |
8.3 下一步 #
现在你已经掌握了常用中间件,接下来让我们学习 请求处理,深入了解Gin的请求处理机制!
最后更新:2026-03-28