我基本上是在尝试编写反向代理服务器,以便在我curl localhost:8080/get
时将其代理到https://nghttp2.org/httpbin/get
。
注意:上面列出的https://nghttp2.org/httpbin/get服务是http / 2。但是这种行为也会发生在http / 1上,例如https://httpbin.org/get。
为此,我使用httputil.ReverseProxy,并且在重写URL的同时自定义Host
标头,以免将localhost:8080
泄漏到实际的后端。
但是,无论我在标头上设置多少次,该请求仍然会使用Host: localhost:8080
到达后端。同样,我使用mitmproxy
监听请求,看起来像net / http。客户端将:authority
伪头设置为localhost:8080
这是我的源代码:
package main
import (
"log"
"net/http"
"net/http/httputil"
)
func main() {
proxy := &httputil.ReverseProxy{
Transport: roundTripper(rt),
Director: func(req *http.Request) {
req.URL.Scheme = "https"
req.URL.Host = "nghttp2.org"
req.URL.Path = "/httpbin" + req.URL.Path
req.Header.Set("Host", "nghttp2.org") // <--- I set it here first
},
}
log.Fatal(http.ListenAndServe(":8080", proxy))
}
func rt(req *http.Request) (*http.Response, error) {
log.Printf("request received. url=%s", req.URL)
req.Header.Set("Host", "nghttp2.org") // <--- I set it here as well
defer log.Printf("request complete. url=%s", req.URL)
return http.DefaultTransport.RoundTrip(req)
}
// roundTripper makes func signature a http.RoundTripper
type roundTripper func(*http.Request) (*http.Response, error)
func (f roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { return f(req) }
当我查询curl localhost:8080/get
时,请求将被代理到https://nghttp2.org/httpbin/get。回显的响应表明,我设置Host
标头的指令显然没有做任何事情:
{
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip",
"Host": "localhost:8080",
"User-Agent": "curl/7.54.0"
},
"origin": "2601:602:9c02:16c2:fca3:aaab:3914:4a71",
"url": "https://localhost:8080/httpbin/get"
}
答案 0 :(得分:4)
来自http.Request
docs:
// For server requests, Host specifies the host on which the URL // is sought. Per RFC 7230, section 5.4, this is either the value // of the "Host" header or the host name given in the URL itself. // It may be of the form "host:port". For international domain // names, Host may be in Punycode or Unicode form. Use // golang.org/x/net/idna to convert it to either format if // needed. // To prevent DNS rebinding attacks, server Handlers should // validate that the Host header has a value for which the // Handler considers itself authoritative. The included // ServeMux supports patterns registered to particular host // names and thus protects its registered Handlers. // // For client requests, Host optionally overrides the Host // header to send. If empty, the Request.Write method uses // the value of URL.Host. Host may contain an international // domain name. Host string
因此,URL.Host
的值仅在request.Host
为空(不是这种情况)的情况下使用。设置request.Host
应该可以解决此问题:
req.Host = "nghttp2.org"
相关问题已讨论here。