目录

背景

近期在处理一个关于网关的需求,主要是对用户的请求转发到后端的服务器集群中。整个设计思路其实还是很简单,通过用户请求过来的路径转发到相应的后端服务器上。比如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,我们可以将请求发送到正确的后端服务器上。如果需要,我们还可以配置传输实现来控制如何与后端服务器通信。

您可能感兴趣的文章: