go 实现反向代理
正向代理和反向代理区别
正向代理
代理的是客户端,隐藏了客户端的真实IP,部署在客户端网络中,访问外部资源,例如通过代理访问外网。
反向代理
代理的是服务端,隐藏了服务端的真实IP,部署在服务端网络中,提供负载均衡,例如访问nginx。
实现反向代理
package main
import (
"log"
"net/http"
"net/http/httputil"
"net/url"
)
func main() {
// 解析目标服务器地址
targetURL, err := url.Parse("http://www.baidu.com")
if err != nil {
log.Fatal(err)
}
// 创建反向代理,监听在8081端口
proxy := httputil.NewSingleHostReverseProxy(targetURL)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 修改请求头,请求目的地址改成目标服务器地址
r.Host = targetURL.Host
// 将请求转发到目标服务器
proxy.ServeHTTP(w, r)
})
log.Println("反向代理服务监听端口8081")
log.Fatal(http.ListenAndServe(":8081", nil))
}
源码分析
func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
director := func(req *http.Request) {
// 重写请求URL
rewriteRequestURL(req, target)
}
return &ReverseProxy{Director: director}
}
func rewriteRequestURL(req *http.Request, target *url.URL) {
targetQuery := target.RawQuery
req.URL.Scheme = target.Scheme
// 重写req的Host,从而把请求转发到后端
req.URL.Host = target.Host
req.URL.Path, req.URL.RawPath = joinURLPath(target, req.URL)
if targetQuery == "" || req.URL.RawQuery == "" {
req.URL.RawQuery = targetQuery + req.URL.RawQuery
} else {
req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
}
}
1. 使用ReverseProxy参数Director修改请求。
2. 设置Header中X-Forward-For值为代理ip。
3. 通过连接池向后端发起请求。
4. 使用ReverseProxy参数ModifyResponse修改响应。
5. 复制后端响应头部、状态码、响应体到代理。