go微服务本身不该处理options预检请求,生产环境必须由api网关或反向代理统一承接并响应;常见原因是nginx等网关默认不转发options而直接返回405/204,且net/http.servemux不自动响应,未显式注册或中间件未覆盖的路径均按405处理。

Go微服务本身不该处理 OPTIONS 预检请求,除非你正本地直连调试;生产环境必须由 API 网关或反向代理统一承接并响应——否则前端永远卡在 405 或无日志。
为什么 Go 服务日志里完全收不到 OPTIONS 请求
常见现象是:前端发 PUT/DELETE 或带 Authorization 头的请求,Network 面板卡在 OPTIONS,状态码显示 405 或直接 pending,但 Go 日志一条记录都没有。
- Nginx、Traefik、Cloudflare 等网关默认不转发
OPTIONS请求——它们可能直接返回204或405,根本不会透传到后端 -
net/http.ServeMux不自动响应OPTIONS,没显式注册或没被中间件覆盖的路径,一律按405 Method Not Allowed处理 - 用了
rs/cors但只 wrap 了/api/子路由,而前端请求的是/health或根路径,OPTIONS仍掉进默认405分支
Nginx 必须显式放行 OPTIONS 才能透传到 Go
别信“Nginx 会自动识别预检”——它不会。默认配置下,limit_except 或缺失 location 块会直接拦截 OPTIONS。
- 在对应
location块中加add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";不够,这只是响应头,不解决透传问题 - 必须显式允许方法:
if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin "*"; add_header Access-Control-Allow-Headers "Content-Type, Authorization, X-Request-ID"; add_header Access-Control-Allow-Credentials "true"; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; add_header Access-Control-Max-Age "86400"; add_header Access-Control-Expose-Headers "X-Total-Count"; add_header Content-Length 0; add_header Content-Type text/plain; return 204; } - 或者更稳妥:用
location ~ ^/.*$ { ... proxy_pass http://go-backend; }并确保没limit_except拦截OPTIONS
本地开发时 rs/cors 的 Options 配置必须严格匹配前端行为
仅当 Go 服务被前端直连(如 http://localhost:3000 → http://localhost:8080)才启用它;此时参数错一个,预检就失败。
-
AllowedOrigins不能写"*"+AllowCredentials: true;必须填具体域名,例如[]string{"http://localhost:3000"} -
AllowedHeaders要和前端实际发送的头完全一致,比如用了X-Request-ID就得加进去,漏一个就会预检失败 -
AllowedMethods必须包含"OPTIONS",否则rs/cors不会拦截并响应它 - 不要手动注册
http.HandleFunc处理OPTIONS——rs/cors会自动处理;若同时写了if r.Method == "OPTIONS",反而可能冲突或重复写 header
生产环境禁止在 Go 服务内写 CORS 响应头
微服务之间走内网调用,不触发同源策略;真正需要跨域头的,只有网关到前端这一跳。把 CORS 逻辑塞进 Go 服务,等于把边界控制权让渡给业务代码。
- 网关层终结
OPTIONS是最干净的做法:Traefik 用corsmiddleware 绑定入口点,它会自动响应,不透传;Cloudflare 可通过规则放行OPTIONS方法 - 自研网关必须检查路由匹配逻辑是否包含
OPTIONS,且不能在鉴权/限流中间件里提前return - 如果硬要在 Go 层兜底,
http.HandlerFunc中的OPTIONS分支必须立即return,不能漏掉,否则后续读r.Body会 panic
最容易被忽略的点是:你以为网关“应该”处理 OPTIONS,但它其实什么都没做;你以为 Go 服务收到了预检,其实它连请求影子都没见着。排查顺序永远是——先看网关日志有没有 OPTIONS 记录,再看 Go 日志有没有,最后才动代码。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











