使用Golang内置http包实现HTTP转HTTPS转发代理的问题咨询
实现方案建议
你原本设计的双端口方案不是最优选择,单端口即可满足后端统一用HTTP交互的需求,实现逻辑更简洁:
- 后端请求代理时,在自定义Header(比如
X-Target-Url)或者请求参数中携带需要转发到的前端服务完整地址 - 代理收到请求后,自动解析目标地址的协议(HTTP/HTTPS),构造对应的出站请求发送给前端服务,后端完全不需要感知前端的协议差异,也不用区分端口接入
现有代码问题修复
你当前代码的核心问题是直接使用了从后端拿到的原始HTTP请求对象转发,请求的URL.Scheme字段还是http,传输层自然不会发起TLS握手,不会自动转成HTTPS请求。
修正后的参考代码如下:
import ( "io" "log" "net/http" "crypto/tls" ) // 假设你从后端拿到的原始请求是r func handleRequest(r *http.Request) { // 克隆原始请求,避免修改原对象影响后续逻辑 outReq := r.Clone(r.Context()) // 手动替换协议为HTTPS outReq.URL.Scheme = "https" // 替换为目标前端服务的域名和端口 outReq.URL.Host = "你的前端服务地址,比如api.example.com" // 必须清空RequestURI字段,net/http的RoundTrip方法不允许该字段有值 outReq.RequestURI = "" egressClient := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, // 生产环境建议关闭,配置合法证书校验逻辑 }, }, } // 推荐用client.Do而非直接调用Transport.RoundTrip,会自动处理重定向等逻辑 resp, err := egressClient.Do(outReq) if err != nil { log.Fatal(err) } defer resp.Body.Close() website, err := io.ReadAll(resp.Body) // Go 1.16+ 推荐用io.ReadAll替代ioutil.ReadAll if err != nil { log.Fatal(err) } log.Print(string(website)) }
注意事项
- 如果需要支持转发到多个不同的前端服务,只需要从后端传过来的参数中提取目标地址的Scheme、Host、Path赋值给出站请求即可
- 生产环境不要开启
InsecureSkipVerify,会存在中间人攻击风险,建议配置系统根证书或者指定前端服务的自签名证书做校验 - 如果需要把前端的响应原封不动返回给后端,不要手动读取响应Body再回写,直接拷贝响应头、状态码、Body流即可,性能更高也不会丢失Header参数
内容的提问来源于stack exchange,提问作者Anupam Asok
相关产品推荐
相关产品推荐

