我无法使用反向代理更改主机头(Host header)。

huangapple go评论66阅读模式
英文:

I can't change the Host header using reverse proxy

问题

我正在为我的后端构建一个反向代理,但我无法理解为什么即使我使用文档中看到的任何方法更改主机头,它也不会改变。
后端需要真实的主机来提供正确的内容。

以下是代码:

proxy := &httputil.ReverseProxy{
	Director: func(req *http.Request) {
		targetURL := url.URL{
			Scheme: "http",
			Host:   "backend.com",
			Path:   req.URL.Path,
		}

		req.URL.Scheme = targetURL.Scheme
		req.URL.Host = targetURL.Host
		req.URL.Path = targetURL.Path
		req.Header.Set("Host", targetURL.Host)

	},
	Transport: transport,
}

// 在本地端口上监听并提供无缓冲方法的反向代理
server := &http.Server{
	Addr:    "localhost:8080",
	Handler: proxy,
}
fmt.Println("正在监听 :8080...")
err = server.ListenAndServe()
if err != nil {
	fmt.Println(err)
}
英文:

I'm building a reverse proxy for my backend but I can't understand why even if I change the host header with any method I've seen in the documentation It won't change.
The backend need the real host in order to serve the right content.

Here is the code:

proxy := &httputil.ReverseProxy{
	Director: func(req *http.Request) {
		targetURL := url.URL{
			Scheme: "http",
			Host:   "backend.com",
			Path:   req.URL.Path,
		}

		req.URL.Scheme = targetURL.Scheme
		req.URL.Host = targetURL.Host
		req.URL.Path = targetURL.Path
		req.Header.Set("Host", targetURL.Host)

	},
	Transport: transport,
}

// Listen on a local port and serve the reverse proxy without buffer method
server := &http.Server{
	Addr:    "localhost:8080",
	Handler: proxy,
}
fmt.Println("Listening on :8080...")
err = server.ListenAndServe()
if err != nil {
	fmt.Println(err)
}

答案1

得分: 2

如果您可以使用go1.20中添加的(*ProxyRequest).SetURL,那么操作将非常简单:

proxy := &httputil.ReverseProxy{
	Rewrite: func(pr *httputil.ProxyRequest) {
		targetURL := url.URL{
			Scheme: "http",
			Host:   "backend.com",
			Path:   req.URL.Path,
		}
		pr.SetURL(&targetURL)
	},
	Transport: transport,
}

有关更多信息,请参见此提案:net/http/httputil: replace Director with Rewrite


如果无法升级到go1.20,以下是Director的解决方法:

proxy := &httputil.ReverseProxy{
	Director: func(req *http.Request) {
		targetURL := url.URL{
			Scheme: "http",
			Host:   "backend.com",
			Path:   req.URL.Path,
		}

		req.URL.Scheme = targetURL.Scheme
		req.URL.Host = targetURL.Host
		req.URL.Path = targetURL.Path
- 		req.Header.Set("Host", targetURL.Host)
+ 		req.Host = targetURL.Host
+ 		// 或者简单地:
+ 		// req.Host = ""
	},
	Transport: transport,
}

请参阅http.Request.Host的文档:

> 对于客户端请求,Host可选地覆盖要发送的Host标头。如果为空,Request.Write方法将使用URL.Host的值。

英文:

If you can use (*ProxyRequest).SetURL added in go1.20, it will be as easy as:

proxy := &httputil.ReverseProxy{
	Rewrite: func(pr *httputil.ProxyRequest) {
		targetURL := url.URL{
			Scheme: "http",
			Host:   "backend.com",
			Path:   req.URL.Path,
		}
		pr.SetURL(&targetURL)
	},
	Transport: transport,
}

See this proposal for more information: net/http/httputil: replace Director with Rewrite.


In the case that it's impossible to upgrade to go1.20, here is a workaround for the Director:

  proxy := &httputil.ReverseProxy{
  	Director: func(req *http.Request) {
  		targetURL := url.URL{
  			Scheme: "http",
  			Host:   "backend.com",
  			Path:   req.URL.Path,
  		}

  		req.URL.Scheme = targetURL.Scheme
  		req.URL.Host = targetURL.Host
  		req.URL.Path = targetURL.Path
- 		req.Header.Set("Host", targetURL.Host)
+ 		req.Host = targetURL.Host
+ 		// or simply:
+ 		// req.Host = ""
  	},
  	Transport: transport,
  }

See the doc for http.Request.Host:

> For client requests, Host optionally overrides the Host header to send. If empty, the Request.Write method uses the value of URL.Host.

huangapple
  • 本文由 发表于 2023年4月30日 19:24:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76140988.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定