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() }, }))}分享文章
生成精美分享图或复制链接,与更多人分享本文。
继续阅读
换条路线
从其他文章中稳定抽取
最后更新于 ,距今已过 89 天
部分内容可能已过时