Gin框架非简单请求(POST JSON)的CORS问题求解,多种方案失效
在localhost:8080部署的网站,通过Axios访问localhost:9999上的Gin服务器时,GET请求正常,但POST请求始终报CORS错误:
Access to XMLHttpRequest at 'http://127.0.0.1:9999/inlog/' from origin 'http://127.0.0.1:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
已尝试三种CORS配置方案,但均无效,代码如下:
func main() { r.Use(cors.Default()) //r.Use(Cors()) //r.Use(Cors1()) r.Use(Cors3()) r.POST("/inlog", func(c *gin.Context) { print(c) c.JSON(200, gin.H{"status": "OK", "message": "pong",}) }) r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", }) }) r.Run(":9999") } func Cors() gin.HandlerFunc { return cors.New(cors.Config{ AllowAllOrigins: true, AllowMethods: []string{"POST", "GET", "PUT", "DELETE", "OPTIONS"}, AllowHeaders: []string{"*"}, ExposeHeaders: []string{"Content-Length", "Authorization", "Content-Type"}, AllowCredentials: true, MaxAge: 12 * time.Hour, }, ) } func Cors1() gin.HandlerFunc { return func(c *gin.Context) { method := c.Request.Method origin := c.Request.Header.Get("Origin") if origin != "" { c.Header("Access-Control-Allow-Origin", origin) c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE") c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization") c.Header("Access-Control-Allow-Credentials", "true") c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") } if method == "OPTIONS" { c.Header("Access-Control-Allow-Origin", origin) c.Header("Access-Control-Allow-Methods", "OPTIONS") c.Header("Access-Control-Allow-Headers", "*") c.AbortWithStatus(http.StatusNoContent) } c.Next() } } func Cors3() gin.HandlerFunc { return func(context *gin.Context) { method := context.Request.Method context.Header("Access-Control-Allow-Origin", "*") context.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token, x-token") context.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH, PUT") context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type") context.Header("Access-Control-Allow-Credentials", "true") if method == "OPTIONS" { context.AbortWithStatus(http.StatusNoContent) } context.Next() } }
1. 修复路由匹配问题
报错中的请求地址是http://127.0.0.1:9999/inlog/(末尾带斜杠),但你的路由定义是/inlog(无斜杠)。Gin路由严格匹配,带斜杠的请求会找不到对应POST路由,返回404,而404响应不会携带CORS头,触发错误。
解决方式二选一:
- 修改Axios请求地址,去掉末尾斜杠,改为
http://127.0.0.1:9999/inlog - 在Gin中添加带斜杠的路由:
r.POST("/inlog/", ...),同时匹配两种请求格式
2. 简化CORS配置,排除自定义逻辑漏洞
自定义中间件可能存在逻辑冲突,推荐直接使用官方github.com/gin-contrib/cors包,先配置最简化规则验证:
import "github.com/gin-contrib/cors" func main() { r := gin.Default() // 最简CORS配置 r.Use(cors.New(cors.Config{ AllowAllOrigins: true, AllowMethods: []string{"GET", "POST", "OPTIONS", "PUT", "DELETE"}, AllowHeaders: []string{"*"}, })) r.POST("/inlog", func(c *gin.Context) { c.JSON(200, gin.H{"status": "OK", "message": "pong"}) }) r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{"message": "pong"}) }) r.Run(":9999") }
3. 确保OPTIONS请求正确处理
跨域POST会先发送OPTIONS预检请求,若中间件未正确处理则预检失败。官方cors包会自动处理OPTIONS请求,无需手动编写逻辑。
若坚持自定义中间件,需注意:
- 处理OPTIONS请求时,必须先设置所有CORS头,再调用
AbortWithStatus(http.StatusNoContent) - 避免在OPTIONS分支中设置冲突的头(比如Cors1中同时设置Allow-Methods为OPTIONS和多种方法)
4. 验证响应头是否生效
用curl发送OPTIONS请求,检查响应头是否包含Access-Control-Allow-Origin:
curl -X OPTIONS -H "Origin: http://127.0.0.1:8080" -i http://127.0.0.1:9999/inlog
若响应头无该字段,说明中间件未生效,检查是否在路由注册前调用了r.Use(corsMiddleware)(中间件必须在路由定义前加载)
内容的提问来源于stack exchange,提问作者Iteravse

