浏览器如何知道哪些标头添加到请求中



当我在浏览器的地址栏中输入站点的 url 时,浏览器会发送请求以通过 url 获取资源。但是当我访问不同的网站(google.com、amazon.com 等(时,初始化页面的请求对不同的站点有不同的标头。

如果浏览器在第一次初始化时只有有关此资源的 URL 的信息,浏览器在哪里获取用于加载页面的请求标头集?

例如,当我转到浏览器 google.com 发送此类请求标头时:

:authority: www.google.com
:method: GET
:path: /
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9,ru-RU;q=0.8,ru;q=0.7
cache-control: max-age=0
sec-fetch-dest: document
sec-fetch-mode: navigate
sec-fetch-site: same-origin
sec-fetch-user: ?1
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36

对于 amazon.com,请求的标头是不同的:

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,ru-RU;q=0.8,ru;q=0.7
Connection: keep-alive
Host: amazon.com
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36

当您在地址栏中输入 URL 时,需要将其转换为 HTTP 请求。

因此,键入 www.google.com 意味着您需要从该服务器GET默认页面(/(。这基本上涵盖了第一个请求的前 4 行中的所有内容。

浏览器还知道它可以accept什么类型的格式。大多数情况下,我们返回 HTML,所以text/html肯定在那里,但我们也接受其他格式 - 包括完全通用的*/*顺便说一句!:-)

请求经常被压缩(使用gzipdeflate或较新的brotli(br(格式(,因此浏览器告诉服务器它在accept-encoding标头中支持哪些格式。

安装浏览器时,您还设置了默认语言,以便我们可以告诉服务器。某些服务器将基于此返回不同的内容。

然后是一些安全标头(我不会详细介绍这些标头,因为非常复杂(。

最后,我们有了user-agent标头。 这基本上是浏览器告诉服务器它是Chrome,还是Firefox或其他任何东西的地方。但由于历史原因,它比"Chrome"长得多。

所以基本上请求标头是浏览器发送到服务器的东西,以提供有关浏览器及其功能的更多信息。对于刚刚在浏览器中键入的请求,无论 URL 是什么,请求标头基本上都是相同的。对于页面提出的其他请求 - 例如通过JavaScript代码,如果它添加更多标题,它们可能会有所不同。

至于您给出的两个示例请求之间的差异:

谷歌使用HTTP/2(如果使用Chrome,则使用QUIC,但就此问题而言,目前基本上是HTTP/2(。 如果将"协议"列添加到"开发人员工具",则可以看到此信息。

HTTP/2 与 HTTP/1 相比有一些变化,即:

  • HTTP 标头名称为小写。从技术上讲,在HTTP/1中,它们不区分大小写,但按照惯例,许多工具(如浏览器(使用标题大小写(每个单词的首字母大写(。
  • 请求(例如GET / HTTP/1.1( 转换为以冒号开头的伪标头 (:method: GET:path: /...等(。
  • Host基本上:authority在HTTP/2中。
  • :scheme基本上是HTTP/2中的新功能,因为以前它不是HTTP请求的明确部分,而是在连接级别处理。
  • Connection在 HTTP/2 中已失效。即使在HTTP/1.1中,它也默认为keep-alive因此不需要上面的标头,但是由于历史原因,许多浏览器和其他客户端都发送了它。

我认为这解释了所有的差异。

那么浏览器如何知道是使用 HTTP/2 还是 HTTP/1.1呢?这已经在堆栈溢出上有了答案,但基本上是在建立HTTPS会话时决定的,如果服务器建议它可以支持HTTP/2并且浏览器想要使用它。

最新更新