gorilla/handlers.cors是最快最稳方案,手写中间件易因漏处理options、credentials与*冲突、header设置过晚导致404或静默失败;根本原因是defaultservemux不处理options请求,预检直接失败。

直接用 gorilla/handlers.CORS 是最快、最稳的方式;手写中间件看似简单,但容易因漏处理 OPTIONS、Access-Control-Allow-Credentials 与 * 冲突、header 设置过晚等问题导致静默失败或 404。
为什么手写 corsMiddleware 常见 404 或 Network 面板里看不到响应
根本原因不是“没加头”,而是没走通浏览器预检流程:
-
http.DefaultServeMux对OPTIONS方法无默认路由,请求压根没进你的 handler,直接 404 -
Access-Control-Allow-Origin: "*"和Access-Control-Allow-Credentials: "true"同时存在 → 浏览器强制丢弃整个响应,Network 面板里 status 都不显示 - 在
w.WriteHeader()或首次w.Write()之后调用w.Header().Set()→ 完全无效,header 不会发出 - 前端发了
X-Auth-Token,但后端没在Access-Control-Allow-Headers里声明 → 预检直接 403,错误提示明确说 header 不在白名单
gorilla/handlers.CORS 怎么用才不出错
它自动拦截并响应 OPTIONS,且所有 header 都在正确时机设置,但默认行为有隐含约束:
- 安装:
go get github.com/gorilla/handlers - 基础用法:
http.ListenAndServe(":8080", handlers.CORS(handlers.AllowedOrigins([]string{"https://myapp.com"}))(r)) -
AllowedOrigins([]string{"*"})时,handlers.AllowCredentials()会被自动禁用——这是对规范的主动校验,不是 bug - 要支持 cookie,必须同时写:
handlers.AllowedOrigins([]string{"https://myapp.com"}), handlers.AllowCredentials() - 暴露自定义响应头(如
X-Request-ID)需显式加:handlers.ExposedHeaders([]string{"X-Request-ID"})
GIN 用户别自己写 c.Header(),必须用 gin-contrib/cors
gin.Context 的 c.Writer 是封装过的响应体,手写 c.Header().Set() 极易绕过中间件链:
-
OPTIONS响应不全(缺Allow-Methods或Allow-Headers) - 带
credentials的请求因Origin与*冲突被拦截,但控制台无明确报错 - 后续中间件覆盖你写的 header,实际发出的和你以为的不一致
- 正确做法:
import "github.com/gin-contrib/cors",然后r.Use(cors.New(cors.Config{AllowOrigins: []string{"https://myapp.com"}}))
验证 CORS 是否真生效,别只看前端页面跑通
真正的问题往往卡在预检阶段,而浏览器控制台只报模糊错误。必须打开 Network 面板,逐项核对:
- 发起的是
OPTIONS请求吗?状态码是 200/204 吗? - 响应头里是否有
Access-Control-Allow-Origin,值是否匹配请求头的Origin? -
Access-Control-Allow-Headers是否包含前端实际发送的自定义头(比如X-User-ID)? - 如果用了
credentials,Access-Control-Allow-Origin绝不能是"*",必须精确匹配 -
Vary: Origin是否存在?缺失会导致 CDN 缓存污染,不同 origin 请求拿到错误响应
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











