使用Go构建反向代理访问GCP Cloud Run实例返回404问题排查
问题根因
Go标准库net/http发起请求时,优先读取http.Request结构体的Host字段作为实际发送的Host请求头,req.Header中设置的Host值会被直接覆盖。你当前代码仅修改了请求头中的Host,没有更新req.Host字段,导致Cloud Run无法正确识别请求对应的服务实例,返回默认404错误。
需要调整的配置点
- 移除请求头中设置Host的逻辑,改为直接对
req.Host赋值为你的Cloud Run域名 - 删除发往Cloud Run的请求头中
Access-Control-Allow-Origin配置,该参数为跨域响应头,添加在请求头中无实际作用 - 可选:初始化反向代理时直接传入正确的HTTPS协议地址,避免后续重复修改Scheme
修正后完整代码
package main import ( "log" "net/http" "net/http/httputil" "net/url" ) const apiUrl = "MY_CLOUD_RUN.a.run.app" func main() { http.HandleFunc("/", proxy) log.Fatal(http.ListenAndServe(":8081", nil)) } func proxy(res http.ResponseWriter, req *http.Request) { // 处理CORS预检请求 if req.Method == http.MethodOptions { headers := res.Header() headers.Add("Access-Control-Allow-Origin", "*") headers.Add("Vary", "Origin") headers.Add("Vary", "Access-Control-Request-Method") headers.Add("Vary", "Access-Control-Request-Headers") headers.Add("Access-Control-Allow-Headers", "*") headers.Add("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE") res.WriteHeader(http.StatusOK) return } p := httputil.NewSingleHostReverseProxy(&url.URL{ Scheme: "https", Host: apiUrl, }) p.Director = func(req *http.Request) { req.Header.Add("X-Forwarded-Host", req.Host) req.Header.Add("X-Origin-Host", apiUrl) // 核心修复:直接赋值Host字段 req.Host = apiUrl req.URL.Scheme = "https" req.URL.Host = apiUrl } p.ModifyResponse = func(res *http.Response) error { res.Header.Set("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE") res.Header.Set("Access-Control-Allow-Credentials", "true") res.Header.Set("Access-Control-Allow-Origin", "*") res.Header.Set("Access-Control-Allow-Headers", "*") return nil } p.ServeHTTP(res, req) }
补充注意事项
如果修改后仍然返回404,可以确认以下两点:
- Cloud Run服务的Ingress规则是否允许你的代理服务器IP访问
apiUrl配置的域名是否和Cloud Run控制台提供的服务访问域名完全一致
内容的提问来源于stack exchange,提问作者djneely
相关产品推荐
相关产品推荐

