Go客户端不报origin not allowed错误,该错误源于浏览器CORS限制:HTTP需在WriteHeader前设Access-Control-Allow-Origin等头,WebSocket需自定义Upgrader.CheckOrigin,带credentials时Origin不能为*且须配Access-Control-Allow-Credentials:true。

Go 客户端本身不会报 origin not allowed 错误——这是浏览器的限制,不是 Go 程序的问题。你看到这个错误,说明实际运行环境是浏览器(比如前端用 JS 调 Go 启的 HTTP 服务),而 Go 服务端没正确响应 CORS 预检或头信息。
为什么 Go 服务返回 origin not allowed
这个错误通常来自两个地方:
- 浏览器控制台显示
Origin http://localhost:3000 is not allowed by Access-Control-Allow-Origin:说明 Go 服务没设Access-Control-Allow-Origin,或设了"*"却又开了credentials - WebSocket 连接时 panic 或报错
request origin not allowed by Upgrader.CheckOrigin:这是gorilla/websocket默认拒绝非同源请求,必须显式覆盖CheckOrigin
HTTP 接口跨域:必须在 WriteHeader 前设置头
Access-Control-Allow-Origin 等头必须在 w.WriteHeader() 或第一次 w.Write() 之前调用,否则完全无效,且无任何提示。
常见错误写法:
func handler(w http.ResponseWriter, r *http.Request) {
// ✅ 正确:头在最前
w.Header().Set("Access-Control-Allow-Origin", "https://a.com")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusNoContent)
return
}
// ❌ 错误:下面这行如果提前触发了 WriteHeader(比如 json.NewEncoder(w).Encode(...))
// 就会导致上面所有 Header.Set() 失效
json.NewEncoder(w).Encode(data)
}
建议统一用中间件,避免漏写或顺序错乱。
WebSocket 跨域:Upgrader.CheckOrigin 必须显式放行
gorilla/websocket 的 Upgrader 默认只允许同源请求。跨域连接会直接失败并抛出 request origin not allowed by Upgrader.CheckOrigin。
解决方法只有改 CheckOrigin 函数:
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
// 开发环境可全放行;生产环境应校验 Origin header
return true
},
}
注意:CheckOrigin 返回 true 不代表不安全——它只是让升级继续,后续仍可做鉴权(如检查 token、session)。但别在生产环境无条件返回 true,尤其当接口暴露公网时。
带 credentials 的请求被静默拦截
前端用了 fetch(url, { credentials: 'include' }) 或设置了 withCredentials: true,后端却写了:
-
w.Header().Set("Access-Control-Allow-Origin", "*")→ 浏览器直接丢弃响应(Network 面板里 status 是 200,但 response body 为空) - 没加
w.Header().Set("Access-Control-Allow-Credentials", "true")→ 请求被拦,且控制台可能只报 CORS 错误,不提 credentials
正确做法:
- Origin 必须写具体值,比如
"https://myapp.com",不能是"*" - 必须同时设置
Access-Control-Allow-Credentials: true - 确保预检 OPTIONS 响应也包含这两个头(中间件里统一设更稳)
最容易被忽略的是:Nginx 反向代理时默认不透传 Access-Control-Allow-* 头,需要显式配置 add_header 并开启 underscores_in_headers off,否则头会被丢弃。


















