Go语言实现CORS需精确匹配Origin并显式声明响应头:允许特定域名时设Access-Control-Allow-Origin为该域名;携带凭证时必须禁用通配符、启用AllowCredentials且Origin严格匹配;推荐使用rs/cors库自动处理预检与校验。
在 Go 语言中实现跨域资源共享(CORS),关键是在 HTTP 响应头中正确设置 Access-Control-Allow-Origin 等字段,并只允许你信任的指定域名,而非使用通配符 *(尤其当携带凭证时不可用)。
如果前端请求不携带 Cookie 或 Authorization 头(即 credentials: false),可直接在响应头中写死目标域名:
Origin 是否在白名单内(如 https://example.com)Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods 和 Access-Control-Allow-Headers
示例(使用标准 net/http):
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(f
unc(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get("Origin")
allowedOrigins := []string{"https://example.com", "https://admin.example.org"}
isAllowed := false
for _, o := range allowedOrigins {
if origin == o {
isAllowed = true
break
}
}
if isAllowed {
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
}
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
当前端设置 credentials: true(例如发送 Cookie 或 Bearer Token),Access-Control-Allow-Origin **不能为 ***,且必须精确匹配 Origin。同时需显式开启:
立即学习“go语言免费学习笔记(深入)”;
Access-Control-Allow-Credentials: trueAccess-Control-Allow-Origin 是单个具体域名(如 https://app.example.com)Origin: https://app.example.com 但 Allow-Origin: * 的响应注意:此时无法用通配子域(如 https://*.example.com),需手动比对或使用正则(谨慎验证)。
用 rs/cors 库可更安全、灵活地管理策略:
import "github.com/rs/cors"
handler := cors.New(cors.Options{
AllowedOrigins: []string{"https://example.com", "https://dashboard.example.net"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowedHeaders: []string{"Content-Type", "Authorization"},
ExposedHeaders: []string{"X-Total-Count"},
AllowCredentials: true,
}).Handler(yourMux)
它自动处理预检(OPTIONS)、Origin 校验、Header 注入,避免手写逻辑出错。
Access-Control-Allow-Origin: * 同时设 AllowCredentials: true —— 这会导致浏览器直接拦截Origin 和 Allow-Origin 是否一致/api/v1),CORS 配置与路由无关,只取决于 HTTP 请求头不复杂但容易忽略细节,核心就是“精确匹配 + 显式声明 + 拒绝默认通配”。