You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gin框架路由组CORS异常:/auth正常/todos报错求助

Golang Gin + Angular 18 CORS问题:部分路由缺失响应头解决方案

问题定位

你的场景是部分路由正常、部分路由触发CORS错误,核心原因是:/api/v1/todos及子路由的请求没有被CORS中间件处理,响应中缺少Access-Control-Allow-Origin头,而/api/v1/auth/login的请求正确经过了CORS中间件。

常见诱因及修复方案

1. 路由注册顺序错误(最可能)

Gin的中间件是按注册顺序加入路由处理链的,如果CORS中间件在路由之后注册,已注册的路由不会应用该中间件。

错误示例:

func main() {
    r := gin.Default()

    // 先注册路由,后加CORS中间件——无效
    authGroup := r.Group("/api/v1/auth")
    authGroup.POST("/login", auth.LoginHandler)

    todoGroup := r.Group("/api/v1/todos")
    todoGroup.GET("/", todo.GetTodosHandler)

    r.Use(cors.Default()) // 中间件不会作用到上面的路由
    r.Run(":8080")
}

修复:

把CORS中间件放在所有路由注册之前,确保全局路由都能继承:

func main() {
    r := gin.Default()

    // 第一步:配置并注册CORS中间件
    corsConfig := cors.DefaultConfig()
    corsConfig.AllowOrigins = []string{"http://localhost:4200"} // 明确指定前端地址
    corsConfig.AllowMethods = []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}
    corsConfig.AllowHeaders = []string{"Origin", "Content-Type", "Authorization"}
    r.Use(cors.New(corsConfig))

    // 第二步:注册所有业务路由
    authGroup := r.Group("/api/v1/auth")
    authGroup.POST("/login", auth.LoginHandler)

    todoGroup := r.Group("/api/v1/todos")
    todoGroup.GET("/", todo.GetTodosHandler)
    todoGroup.GET("/:id", todo.GetTodoHandler)
    // 其他todos路由...

    r.Run(":8080")
}

2. Todos路由分组未继承全局中间件

如果创建todos路由分组时手动指定了中间件,但未保留全局中间件的继承,会导致CORS中间件失效。

错误示例:

// 分组时仅添加自定义中间件,覆盖了全局中间件
todoGroup := r.Group("/api/v1/todos", todo.AuthMiddleware)

修复:

要么让分组自动继承全局中间件,再手动添加自定义中间件;要么显式加入CORS中间件:

// 方式1:先创建分组,再添加自定义中间件(继承全局)
todoGroup := r.Group("/api/v1/todos")
todoGroup.Use(todo.AuthMiddleware)

// 方式2:显式包含CORS中间件
todoGroup := r.Group("/api/v1/todos", cors.New(corsConfig), todo.AuthMiddleware)

3. 自定义中间件提前返回未设置CORS头

如果todos路由有前置中间件(如权限校验),在验证失败时直接返回响应但未设置CORS头,也会触发错误。

错误示例:

func AuthMiddleware(c *gin.Context) {
    token := c.GetHeader("Authorization")
    if token == "" {
        // 直接返回401,未设置CORS头
        c.JSON(http.StatusUnauthorized, gin.H{"error": "无权限"})
        c.Abort()
        return
    }
    c.Next()
}

修复:

确保CORS中间件在所有业务中间件之前执行(按注册顺序),这样即使业务中间件提前返回,CORS头也已经被设置。

4. 预检请求(OPTIONS)未被正确处理

浏览器对非简单请求(如带自定义头的GET)会先发OPTIONS预检请求,如果后端未正确响应,会触发CORS错误。

用github.com/gin-contrib/cors包的默认配置会自动处理OPTIONS请求,但如果是自定义中间件,必须显式处理:

func CORSMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Writer.Header().Set("Access-Control-Allow-Origin", "http://localhost:4200")
        c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
        c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Authorization")

        // 处理OPTIONS预检请求
        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(http.StatusNoContent)
            return
        }

        c.Next()
    }
}

验证方法

用curl发送OPTIONS请求验证CORS头是否存在:

curl -X OPTIONS -H "Origin: http://localhost:4200" -i http://localhost:8080/api/v1/todos

如果响应头包含Access-Control-Allow-Origin: http://localhost:4200,说明中间件已生效。

内容的提问来源于stack exchange,提问作者Jahid Hasan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 02:37:32