886 字
4 分钟
中间件

全局中间件#

func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
t := time.Now()
// 设置变量
c.Set("example", "12345")
// 请求前
log.Printf("Before request")
c.Next()
// 请求后
latency := time.Since(t)
log.Printf("Latency: %v", latency)
status := c.Writer.Status()
log.Printf("Status: %d", status)
}
}
func main() {
r := gin.New()
// 使用全局中间件
r.Use(Logger())
r.Use(gin.Recovery())
r.GET("/test", func(c *gin.Context) {
example := c.MustGet("example").(string)
c.JSON(http.StatusOK, gin.H{
"example": example,
})
})
r.Run(":8080")
}

路由中间件#

func AuthRequired() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "Authorization required",
})
c.Abort()
return
}
// 验证 token
if token != "valid-token" {
c.JSON(http.StatusUnauthorized, gin.H{
"error": "Invalid token",
})
c.Abort()
return
}
c.Next()
}
}
func main() {
r := gin.Default()
// 公开路由
r.GET("/public", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Public endpoint",
})
})
// 受保护的路由
r.GET("/protected", AuthRequired(), func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Protected endpoint",
})
})
r.Run(":8080")
}

分组中间件#

func main() {
r := gin.Default()
// 公开 API
public := r.Group("/api/public")
{
public.GET("/info", getInfo)
}
// 需要认证的 API
authorized := r.Group("/api/private")
authorized.Use(AuthRequired())
{
authorized.GET("/profile", getProfile)
authorized.POST("/update", updateProfile)
}
// 管理员 API
admin := r.Group("/api/admin")
admin.Use(AuthRequired(), AdminRequired())
{
admin.GET("/users", getAllUsers)
admin.DELETE("/user/:id", deleteUser)
}
r.Run(":8080")
}
func getInfo(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"info": "public"})
}
func getProfile(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"profile": "user profile"})
}
func updateProfile(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "Profile updated"})
}
func getAllUsers(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"users": []string{}})
}
func AdminRequired() gin.HandlerFunc {
return func(c *gin.Context) {
role := c.GetHeader("X-User-Role")
if role != "admin" {
c.JSON(http.StatusForbidden, gin.H{
"error": "Admin access required",
})
c.Abort()
return
}
c.Next()
}
}

常用中间件#

CORS 跨域中间件#

func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
func main() {
r := gin.Default()
r.Use(CORSMiddleware())
r.GET("/api/data", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"data": "CORS enabled",
})
})
r.Run(":8080")
}

限流中间件#

import (
"golang.org/x/time/rate"
"sync"
)
func RateLimitMiddleware(r rate.Limit, b int) gin.HandlerFunc {
limiters := &sync.Map{}
return func(c *gin.Context) {
ip := c.ClientIP()
limiterInterface, _ := limiters.LoadOrStore(ip, rate.NewLimiter(r, b))
limiter := limiterInterface.(*rate.Limiter)
if !limiter.Allow() {
c.JSON(http.StatusTooManyRequests, gin.H{
"error": "Too many requests",
})
c.Abort()
return
}
c.Next()
}
}
func main() {
r := gin.Default()
// 每秒最多 5 个请求,突发 10 个
r.Use(RateLimitMiddleware(5, 10))
r.GET("/api/data", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "Success",
})
})
r.Run(":8080")
}

JWT 认证中间件#

import (
"github.com/golang-jwt/jwt/v5"
"time"
)
var jwtSecret = []byte("your-secret-key")
type Claims struct {
UserID uint `json:"user_id"`
Username string `json:"username"`
jwt.RegisteredClaims
}
func GenerateToken(userID uint, username string) (string, error) {
claims := Claims{
UserID: userID,
Username: username,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
Issuer: "gin-app",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
func ParseToken(tokenString string) (*Claims, error) {
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
return claims, nil
}
return nil, jwt.ErrSignatureInvalid
}
func JWTAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"})
c.Abort()
return
}
// 移除 "Bearer " 前缀
if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
tokenString = tokenString[7:]
}
claims, err := ParseToken(tokenString)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
c.Abort()
return
}
c.Set("user_id", claims.UserID)
c.Set("username", claims.Username)
c.Next()
}
}
func main() {
r := gin.Default()
r.POST("/login", func(c *gin.Context) {
var loginForm struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
if err := c.ShouldBindJSON(&loginForm); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 验证用户(示例)
if loginForm.Username == "admin" && loginForm.Password == "password" {
token, err := GenerateToken(1, loginForm.Username)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"})
return
}
c.JSON(http.StatusOK, gin.H{
"token": token,
})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
}
})
// 受保护的路由
authorized := r.Group("/api")
authorized.Use(JWTAuthMiddleware())
{
authorized.GET("/profile", func(c *gin.Context) {
userID := c.GetUint("user_id")
username := c.GetString("username")
c.JSON(http.StatusOK, gin.H{
"user_id": userID,
"username": username,
})
})
}
r.Run(":8080")
}

统一错误处理中间件#

type APIError struct {
Code int `json:"code"`
Message string `json:"message"`
}
func ErrorHandler() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
// 检查是否有错误
if len(c.Errors) > 0 {
err := c.Errors.Last()
// 根据错误类型返回不同的响应
switch err.Type {
case gin.ErrorTypeBind:
c.JSON(http.StatusBadRequest, APIError{
Code: 400,
Message: err.Error(),
})
case gin.ErrorTypePublic:
c.JSON(http.StatusInternalServerError, APIError{
Code: 500,
Message: err.Error(),
})
default:
c.JSON(http.StatusInternalServerError, APIError{
Code: 500,
Message: "Internal server error",
})
}
}
}
}
func main() {
r := gin.Default()
r.Use(ErrorHandler())
r.GET("/error", func(c *gin.Context) {
// 添加错误
c.Error(errors.New("Something went wrong"))
})
r.Run(":8080")
}

CSRF 防护中间件#

import "github.com/gin-contrib/csrf"
func main() {
r := gin.Default()
r.Use(csrf.Middleware(csrf.Options{
Secret: "secret-key",
ErrorFunc: func(c *gin.Context) {
c.JSON(http.StatusForbidden, gin.H{"error": "CSRF token invalid"})
c.Abort()
},
}))
}
中间件
https://shirone.mysqil.com/posts/gin/中间件/
作者
HikariTish
发布于
2026-07-18
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取