go version需≥1.18,path冲突时优先使用官方路径;cors必须在网关层处理,options预检需显式拦截;allowcredentials为true时allowedorigins不可用*;gin推荐用gin-contrib/cors中间件并注意vary: origin头。

go version 一查就知,别急着重装
很多问题根本不是没装 Go,而是版本太旧或 PATH 混乱。先跑 go version,输出得是 go1.18 或更高——低于这个版本,go mod 默认行为、泛型支持都可能出问题。如果提示 command not found,再查 which go(macOS/Linux)或 where go(Windows),看是不是同时存在多个 go 二进制,比如 /usr/local/go/bin/go 和 ~/sdk/go1.20.5/bin/go。冲突时优先用官方压缩包解压到 /usr/local/go(macOS/Linux)或 C:\Go(Windows),然后只把对应 bin 目录加进 PATH。
go mod init 后,CORS 配置必须在网关或入口层做
跨域不是某个 handler 里加几行头就能搞定的事。浏览器发带 credentials 或自定义 header 的请求前,必先发 OPTIONS 预检。如果网关不拦截,直接把 OPTIONS 转给下游服务,而下游没注册该路由,就会返回 405 或 404,前端控制台只显示 “CORS error”,连具体哪条头没回都不知道。
-
rs/cors默认不拦截OPTIONS,必须显式设OptionsPassthrough: false -
gorilla/handlers.CORS()默认拦截并返回204空响应,更省心,但要确认下游没重复挂 CORS 中间件,否则头被写两次会报错 - 手写中间件时,
r.Method == "OPTIONS"分支必须w.WriteHeader(http.StatusNoContent)并立刻 return,不能继续调用下游逻辑
AllowCredentials = true 时,AllowedOrigins 不能是 "*"
这是浏览器硬性限制,不是后端能绕过的。一旦你设了 Access-Control-Allow-Credentials: "true"(注意:字符串,不是布尔值),同时 Access-Control-Allow-Origin 是 "*",整个响应会被静默丢弃——前端控制台甚至不报错,只卡在 pending 状态。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 开发环境可写死:
[]string{"http://localhost:3000", "http://127.0.0.1:3000"} - 生产环境必须动态校验:从
r.Header.Get("Origin")提取完整协议+域名+端口,比对白名单(注意https://example.com≠https://example.com/),匹配成功才回写该 Origin - 子域名通配(如
"*.example.com")不被标准支持,得自己用strings.HasSuffix或正则判断
Gin 项目里加 CORS,别在每个 handler 里手动写
Gin 本身没内置 CORS,但中间件方式最干净。用 github.com/gin-contrib/cors(不是 gorilla 那个)更贴合 Gin 生态,配置也直观:
import "github.com/gin-contrib/cors"
r := gin.Default()
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"https://app.example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Content-Type", "Authorization"},
AllowCredentials: true,
}))
关键点:这个中间件必须在 r.GET 之前注册;AllowCredentials: true 时,AllowOrigins 列表里不能有 "*";如果要用动态 origin,得自己写回调函数传给 cors.Config 的 AllowOriginFunc 字段,而不是靠字符串匹配。
真正容易漏的是 Vary: Origin 头——它告诉 CDN 或代理不能缓存这个响应。gin-contrib/cors 和 rs/cors 都自动加,但手写中间件时得自己补上,否则缓存可能把 A 域名的响应返回给 B 域名。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










