目录
背景
近期在处理一个关于网关的需求,主要是对用户的请求转发到后端的服务器集群中。整个设计思路其实还是很简单,通过用户请求过来的路径转发到相应的后端服务器上。比如A和B两个服务,当访问test.cn:8080 时网关将请求转发到后端服务A,当访问test.cn:8080/images 时网关把请求转发到后端服务B吧。本文主要是实践下 Go 提供的 httputil 包中的ReverseProxy类型,它可以帮助我们快速地实现HTTP反向代理。
ReverseProxy
ReverseProxy类型是一个HTTP处理器,用于将客户端的请求转发到另一个HTTP服务器上。ReverseProxy有两个主要的字段:Director和Transport。
- Director函数:用于修改请求的URL和Header,以便将请求发送到正确的后端服务器上。
Director func(*http.Request)
可以看到 Director 函数是一个回调函数,传递的参数 Http请求,所在在该函数中,可以修改请求路径将其改成真正要请求的服务地址,也可以对 Header 字段进行增加、删除或修改。
- Transport字段:用于控制如何与后端服务器通信。Transport字段是非必选字段,如果未指定,则将使用默认的http.Transport。通过 Transport字段可以控制服务之间如何建立连接,服务通信的证书验证以及设置如何失败重试请求。就是设置对大连接数,最大空闲连接数和超时时间等。
ReverseProxy 例子
下面是一个简单的示例,实现将来自localhost:8080的请求转发到localhost:8888上:
func main() { // 创建反向代理 proxy := httputil.NewSingleHostReverseProxy(&url.URL{ Scheme: "http", Host: "localhost:8888", }) // 创建HTTP服务器 http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, world!") }) // 将反向代理和HTTP服务器绑定在一起 http.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) { proxy.ServeHTTP(w, r) }) // 启动HTTP服务器 if err := http.ListenAndServe(":8080", nil); err != nil { panic(err) } }
另外启动一个端口为 8888的服务,其中提供一个 /api 接口
func main() { http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, From 8888!") }) var err any if err = http.ListenAndServe(":8888", nil); err != nil { panic(err) } }
在上面的示例中,我们首先创建了一个反向代理,并将其配置为将请求发送到localhost:8888。接下来,我们创建了一个HTTP服务器,并将其与反向代理绑定在一起。当客户端请求URL以“/api/”开头时,服务器将使用反向代理将请求转发到后端服务器上。如果客户端请求的URL不以“/api/”开头,则服务器将返回“Hello, world!”的字符串。
当我们运行该程序并向localhost:8080/api发送请求时,就可以看看到来自后端服务器localhost:8888 的响应。结果如下图所示:
结论
使用Go语言的httputil.ReverseProxy,我们可以非常轻松地实现HTTP反向代理。通过在Director函数中修改请求的URL和Header,我们可以将请求发送到正确的后端服务器上。如果需要,我们还可以配置传输实现来控制如何与后端服务器通信。