options预检请求必须返回204 no content,且access-control-allow-origin不能为*(当启用credentials时),中间件注册顺序必须在路由之前。

OPTIONS 预检请求必须返回 204 No Content
浏览器对非简单请求(如 POST 带 application/json、PUT、带自定义 header 或启用 credentials)会先发 OPTIONS 预检。若响应不是 204,Chrome/Safari 可能静默失败——哪怕你返回了 200 OK 或 200 带空 body,也不符合 RFC 规范。
实操建议:
- 中间件中检测到
c.Request.Method == "OPTIONS"后,必须调用c.AbortWithStatus(http.StatusNoContent)(即204),且不能执行c.Next() - 不要用
c.JSON(200, nil)或c.String(200, "")替代,它们会写入响应体,违反预检要求 - 确保该判断放在所有 header 设置之后、
c.Next()之前,否则 header 可能未生效
Access-Control-Allow-Origin 不能为 * 当 AllowCredentials = true
只要中间件或 gin-contrib/cors 中设置了 Access-Control-Allow-Credentials: "true"(比如前端带 withCredentials: true),Access-Control-Allow-Origin 就绝不能是 "*"。浏览器会直接丢弃整个响应,连控制台都不报错——只表现为后续请求卡住、无响应。
实操建议:
- 开发时可硬编码白名单,如
[]string{"http://localhost:3000", "https://dev.example.com"} - 生产环境务必动态校验
Origin请求头,匹配后再写入该 origin 值,而非通配符 - 若用
gin-contrib/cors,避免设AllowAllOrigins: true,改用AllowOriginFunc回调做白名单判断
中间件注册顺序错误导致 CORS 失效
r.Use(corsMiddleware) 必须在 r.GET/r.POST 等路由注册之前调用。如果写在路由后面,中间件根本不会被触发——尤其容易在重构时把 Use 挪到 r.Group 之后,或误塞进某个子路由链里。
实操建议:
- 固定模式:拿到
r := gin.Default()后,**第一行**就写r.Use(corsMiddleware) - 不要在
c.Next()前设置任何响应头(比如提前c.Header(...)),否则OPTIONS可能被截断或覆盖 - 若用
gin-contrib/cors,确认导入的是github.com/gin-contrib/cors,不是拼错成gin-cors等不存在的包
AllowHeaders 和 AllowMethods 必须精确匹配前端实际发送的内容
前端发了 Authorization header,但后端 Access-Control-Allow-Headers 没包含它?浏览器直接拦截。同理,前端用 fetch 发 PATCH,但后端 AllowMethods 只写了 "GET,POST,OPTIONS"?预检失败。
实操建议:
-
AllowHeaders至少包含:"Content-Type, Authorization, X-Requested-With";若前端加了自定义头(如X-Trace-ID),必须显式列出 -
AllowMethods要覆盖所有可能用到的方法,常见需补全:"GET, POST, PUT, DELETE, PATCH, OPTIONS" - 开发期可用
"*"宽松调试,但上线前必须收窄——某些旧版浏览器不支持AllowHeaders: "*"
跨域问题最棘手的不是配置项多,而是错误表现不一致:有时 GET 成功 POST 失败,有时本地 OK 上线炸锅。核心永远就三点:OPTIONS 必须 204、Origin 不能瞎写 *、中间件位置不能错。其他都是枝节。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











