微服务cors必须网关与各服务协同配置:网关需透传options并保留origin头,各服务路由须显式支持options方法,带凭据跨域须动态校验origin且禁用*,vary: origin不可遗漏,内部服务不设cors头。

微服务架构下,CORS 不能只在某个服务里配完就完事——它必须和网关、路由、凭证传递、多源策略联动,否则前端发一个请求,可能卡在网关没透传头、卡在某个服务漏了 OPTIONS、或卡在凭据跨服务时 Access-Control-Allow-Origin 和 Access-Control-Allow-Credentials: true 冲突。
网关层必须透传并统一处理 OPTIONS 预检
微服务通常有 API 网关(如 Kong、Traefik 或自研 Go 网关),但多数默认不处理 OPTIONS,也不转发原始 Origin 头。结果就是:前端发预检,网关直接 404 或返回空响应,后续请求根本不会发出。
- 用 Traefik 时,必须显式开启
cors中间件,并配置origin白名单;若用自定义 Go 网关,需在RoundTrip前拦截r.Method == "OPTIONS",立即返回http.StatusNoContent,且不调用下游 - Nginx 作网关时,
add_header 'Access-Control-Allow-Origin' '$sent_http_access_control_allow_origin' always;必须加always,否则对OPTIONS响应无效 - 网关若做了负载均衡或重写路径,要确保
Origin头未被篡改或丢弃——某些网关会重写Host却忽略Origin,导致后端校验失败
每个微服务不能只依赖全局中间件
即使网关配了 CORS,单个微服务仍可能因路由框架行为差异而失效:比如 gorilla/mux 默认不匹配 OPTIONS 方法,gin 的 gin-contrib/cors 若挂载顺序错,OPTIONS 请求可能压根进不了中间件链。
- 用
gorilla/mux时,每个需跨域的路由必须显式声明.Methods("GET", "POST", "OPTIONS"),不能只写.Methods("GET", "POST")后指望中间件兜底 - 用
gin时,router.Use(cors.New(...))必须放在所有router.Group之前;若在子 group 里单独挂cors,父级路由的OPTIONS可能 404 - 服务间调用(如 A → B)若也走 HTTP,B 服务的 CORS 配置不应启用
AllowCredentials——内部调用不需要浏览器级凭据,设了反而增加攻击面
带 credentials 的跨域必须动态校验 Origin
微服务常对接多个前端:管理后台、小程序、H5 页面,各自域名不同。硬编码白名单(如 []string{"https://admin.com", "https://app.com"})难维护,且无法应对灰度发布或临时调试域名(如 https://dev-abc123.ngrok.io)。
- 用
gorilla/handlers.CORS时,必须换用handlers.AllowedOriginsFunc,自己解析r.Header.Get("Origin")并查配置中心或 DB;注意过滤空值、非法协议(如data:、file://) - 校验逻辑里必须严格比对协议+域名+端口,
https://a.com和http://a.com是两个源,localhost:3000和127.0.0.1:3000也不等价 - 动态校验函数返回
true后,务必手动调用w.Header().Set("Access-Control-Allow-Origin", origin),不能只靠中间件自动填*——因为AllowCredentials: true时,库会拒绝*
Vary: Origin 头漏设会导致缓存污染
微服务常部署在 CDN 或反向代理后,若响应没带 Vary: Origin,同一个缓存响应可能被复用于不同源的请求,造成 Access-Control-Allow-Origin 错配——比如用户 A 的请求缓存后,用户 B 访问时拿到 A 的 Origin 值,浏览器直接报错。
-
gorilla/handlers.CORS和rs/cors会自动加Vary: Origin,手写中间件必须显式补:w.Header().Set("Vary", "Origin") - 若网关做了缓存,需确认其缓存 key 是否包含
Origin头;Kong 默认不包含,需在插件中显式配置cache-key - 开发环境常关 CDN,容易忽略此问题,上线后才暴露——建议压测时用不同
Origin头并发请求,观察响应头是否一致
最易被忽略的是:微服务之间若存在链式调用(A → B → C),而 C 返回了 Access-Control-Allow-Origin,这个头对 A/B 完全无意义——浏览器只认最终响应的服务,其他中间服务的 CORS 头会被忽略。所以 CORS 配置永远只在面向前端的入口服务上做,内部服务保持最小权限原则,不设任何 CORS 头。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











