在 Go 中编写一个简单的反向代理
转自:https://twin.sh/articles/43/writing-a-simple-reverse-proxy-in-go
由于 httputil 包的NewSingleHostReverseProxy
功能,在 Go 中编写反向代理绝对是一种乐趣。
package main
import (
"crypto/tls"
"log"
"net/http"
"net/http/httputil"
"net/url"
"time"
)
var (
targetUrl *url.URL
)
func main() {
var err error
targetUrl, err = url.Parse("https://url-to-direct/")
if err != nil {
panic(err)
}
handler := http.NewServeMux()
handler.HandleFunc("/", proxyHandler)
server := &http.Server{
Addr: ":8080",
Handler: handler,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
IdleTimeout: 15 * time.Second,
}
server.SetKeepAlivesEnabled(true)
log.Printf("Listening on %s\n", server.Addr)
log.Fatal(server.ListenAndServe())
}
func proxyHandler(writer http.ResponseWriter, request *http.Request) {
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
httputil.NewSingleHostReverseProxy(targetUrl).ServeHTTP(writer, request)
}
请注意,如果接收端有反向代理(即 Nginx、Traefik、Ambassador 等),您很可能还需要将请求主机覆盖到目标主机:
func proxyHandler(writer http.ResponseWriter, request *http.Request) {
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
request.Host = targetUrl.Host
httputil.NewSingleHostReverseProxy(targetUrl).ServeHTTP(writer, request)
}
如果您想通过代理上的特定路径公开代理服务,而不是将其公开/
,那么您可以执行以下操作:
handler.HandleFunc("/external-service/", externalServiceHandler)
// ...
func externalServiceHandler(writer http.ResponseWriter, request *http.Request) {
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
request.Host = targetUrl.Host
request.URL.Path = strings.TrimPrefix(request.URL.Path, "/external-service")
httputil.NewSingleHostReverseProxy(targetUrl).ServeHTTP(writer, request)
}
请记住,虽然如果您使用代理来访问 API,这不会导致任何问题,但如果您尝试代理到前端应用程序,则很可能会遇到奇怪的问题,因为绝对和相对路径。