What is the difference between `Host` and `URL.Host` for golang `http.Request`?

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

What is the difference between `Host` and `URL.Host` for golang `http.Request`?

问题

在开发golang的http应用程序时,我经常使用http.Request。当访问请求主机地址时,我会使用req.Host,但我发现req.URL.Host字段存在,但当我打印它时,它是空的。

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("uri Host: " + r.URL.Host + " Scheme: " + r.URL.Scheme)
    fmt.Println("Host: " + r.Host)
}

http.Request的文档给出了以下注释,而net/url没有给出太多线索。

// 对于服务器请求,Host指定了URL所在的主机。
// 根据RFC 2616,这可以是“Host”头的值,也可以是URL本身中给出的主机名。
// 它可以是“host:port”的形式。对于国际域名,Host可以是Punycode或Unicode形式。
// 如果需要,可以使用golang.org/x/net/idna将其转换为任一格式。
//
// 对于客户端请求,Host可选地覆盖Host头进行发送。如果为空,Request.Write方法将使用URL.Host的值。Host可以包含国际域名。
Host string

在请求中,我认为有两个主机值:URI行和Host头,例如:

GET http://localhost:8080/ HTTP/1.1
Host: localhost:8080

但这并没有解决问题,反而引入了更多问题:

  1. 为什么请求中有两个不同的Host字段?这不是重复了吗?
  2. 在同一个请求中,这两个Host字段可以不同吗?
  3. 在什么情况下应该使用哪一个?

最好附带一个真实的HTTP请求示例来回答这些问题。提前感谢您的帮助。

英文:

When developing golang http application, I use http.Request a lot. When accessing request host address, I would use req.Host, but I find that there is req.URL.Host field, but when I print it, it's empty.

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("uri Host: " + r.URL.Host + " Scheme: " + r.URL.Scheme)
    fmt.Println("Host: " + r.Host)
}

The documentation of http.Request gives the following comments, while net/url does not give much clue.

// For server requests Host specifies the host on which the
// URL is sought. Per RFC 2616, 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.
//
// 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

It seems to me that there are two host value in a request: uri line and Host header, like:

GET http://localhost:8080/ HTTP/1.1
Host: localhost:8080

But it does not solve many problems than it creates:

  1. Why are there two different Host field in request? I mean isn't this a duplicate?
  2. Can the two Host fields be different in the same request?
  3. Which one should I use for what situation?

Answers with a real HTTP request example would be the best. Thanks in advance.

答案1

得分: 49

r.URL字段是通过解析HTTP请求URI创建的。

r.Host字段是Host请求头的值。它与调用r.Header.Get("Host")的结果相同。

如果在网络上的HTTP请求如下所示:

 GET /pub/WWW/TheProject.html HTTP/1.1
 Host: www.example.org:8080

那么r.URL.Host是"",r.Hostwww.example.org:8080

r.URL.Hostr.Host的值几乎总是不同的。在代理服务器上,r.URL.Host是目标服务器的主机,而r.Host是代理服务器本身的主机。当不通过代理连接时,客户端在请求URI中不指定主机。在这种情况下,r.URL.Host是空字符串。

如果您不是在实现代理,那么应该使用r.Host来确定主机。

英文:

The r.URL field is created by parsing the HTTP request URI.

The r.Host field is the value of the Host request header. It's the same value as calling r.Header.Get("Host").

If the HTTP request on the wire is:

 GET /pub/WWW/TheProject.html HTTP/1.1
 Host: www.example.org:8080

then r.URL.Host is "" and r.Host is www.example.org:8080.

The value of r.URL.Host and r.Host are almost always different. On a proxy server, r.URL.Host is the host of the target server and r.Host is the host of the proxy server itself. When not connecting through a proxy, the client does not specify a host in the request URI. In this scenario, r.URL.Host is the empty string.

If you are not implementing a proxy, then you should use r.Host to determine the host.

huangapple
  • 本文由 发表于 2017年3月21日 16:17:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/42921567.html
匿名

发表评论

匿名网友

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

确定