go语言原生net/http不处理cors,必须手动或用中间件配置响应头;手写易因未显式处理options、credentials与*冲突、header设置过晚或nginx未透传而失败。

Go 语言原生 net/http 完全不处理 CORS,所有响应头都得你手动加或用中间件补;配错一个字段(比如 Access-Control-Allow-Origin 和 Access-Control-Allow-Credentials: true 同时用 "*"),浏览器就静默丢弃响应——连 Network 面板都看不到完整请求。
为什么手写中间件常卡在 OPTIONS 404
Go 的 http.DefaultServeMux 对 OPTIONS 方法无默认路由逻辑,也不会 fallback 到你的 handler。如果你没显式拦截或注册 OPTIONS 请求,它直接 404,前端根本收不到预检响应。
- 必须在中间件里判断
r.Method == "OPTIONS",并立即调用w.WriteHeader(http.StatusNoContent)返回,不能继续调用next.ServeHTTP() - 不能依赖
http.HandleFunc自动匹配 —— 它只认GET/POST,OPTIONS不在默认支持列表里 - 如果用了
gorilla/mux,必须在HandleFunc().Methods()中显式包含http.MethodOptions,否则中间件拿不到该请求
AllowCredentials 和 * 不能共存是硬性规范
浏览器强制要求:只要响应头含 Access-Control-Allow-Credentials: true(即前端 fetch 设了 { credentials: 'include' }),Access-Control-Allow-Origin 就不能是 "*",必须是具体协议+域名+端口,比如 "https://myapp.com" 或 "http://localhost:3000"。
- 用
gorilla/handlers.CORS时,传handlers.AllowedOrigins([]string{"*"})会自动禁用AllowCredentials,这是库对规范的主动校验,不是 bug - GIN 用户若用
gin-contrib/cors,config.AllowCredentials = true时,config.AllowOrigins数组里绝不能出现"*",否则整个响应被浏览器丢弃 - 动态 origin(如从数据库查白名单)必须用
handlers.AllowedOriginsFunc或cors.Config.AllowOriginFunc,而不是硬编码"*"
header 设置时机错一次就白配
w.Header().Set() 必须在 w.WriteHeader() 或首次 w.Write() 之前调用,否则完全无效——Go 的 Header 是 map,但一旦响应头已写出,再设也进不了网络包。
- 常见错误:在 handler 末尾才写 header,或在
if r.Method == "OPTIONS"分支外统一设,导致OPTIONS响应没带Access-Control-Allow-Methods等关键头 - 用
gorilla/handlers.CORS或gin-contrib/cors可规避此问题,它们在 middleware 入口就完成所有 header 注入 - 若用 Nginx 反代 Go 服务,必须配置
add_header 'Access-Control-Allow-Origin' '$sent_http_access_control_allow_origin' always;,否则 Nginx 不透传后端设置的头
真正容易被忽略的是:CORS 不是“加几个 header 就完事”,而是要覆盖整个请求生命周期——尤其是 OPTIONS 的响应完整性、credentials 与 origin 的互斥关系、以及反向代理层是否透传。哪怕中间件配置正确,Nginx 漏掉 always 参数,生产环境照样失败。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











