【问题标题】:How browser knows which headers add to requests浏览器如何知道哪些标头添加到请求中
【发布时间】:2020-10-04 06:50:58
【问题描述】:

当我在浏览器的地址栏输入网站的 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

【问题讨论】:

  • 您能否在您的问题中添加不同标题的示例?

标签: browser server request http-headers


【解决方案1】:

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

因此,键入 www.google.com 意味着您需要从该服务器GET 默认页面 (/)。这基本上都包含在第一个请求的前 4 行中。

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

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

当您安装浏览器时,您还设置了默认语言,以便我们可以告诉服务器。有些服务器会根据这个返回不同的内容。

然后是一些安全标头(我不会太复杂)。

最后我们有了user-agent 标头。这基本上是浏览器告诉服务器它是 Chrome 还是 Firefox 或其他什么的地方。但是对于historical reasons,它比“Chrome”要长得多。

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

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

Google 使用 HTTP/2(如果使用 Chrome,则为 QUIC,但就这个问题而言,目前基本上是 HTTP/2)。如果您将选项协议列添加到开发人员工具中,您可以看到这一点。

HTTP/2 与 HTTP/1 相比有几个变化,即:

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

我认为这可以解释所有差异。

那么浏览器是如何知道是使用 HTTP/2 还是 HTTP/1.1 呢?哪个already has an answer on Stack Overflow,但是如果服务器建议它可以支持HTTP/2并且浏览器想要使用它,基本上是在建立HTTPS会话时决定的。

【讨论】:

  • 我的意思是,如果我只输入 URL,浏览器如何知道其余信息(请求标头等)。哪种机制允许浏览器知道除了用户输入的 URL 之外的其余信息?一些 DNS 服务器(但它只是用于获取 IP)、设置连接、一些路由器或什么?也许某些较低级别的协议会发送此信息?哪个 OSI 级别取决于它?
  • 如果我说得对,TLS负责选择HTTP协议,TLS负责协议的所有其他数据,包括请求的标头,不是吗?
  • 添加了更多的 cmets。希望这能回答您的问题。
  • 好的,我明白了。那么cache-control: max-age=0 request-header 字段呢?它是由 HTTP/2 还是由服务器通过 TLS 配置的(或者不是 TLS,而是其他协议)?基本上这就是我得到这个问题的原因)
  • 不,那是因为你刷新了第一个页面(所以浏览器说“嘿,这家伙要我检查这是不是最新的页面,所以不要给我任何缓存的旧页面请翻页”),而您第二次没有。如果您刷新 amazon.com,您将看到相同的 cache-control: max-age=0 标头。
猜你喜欢
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
  • 2013-07-23
  • 1970-01-01
  • 2021-03-14
  • 1970-01-01
  • 1970-01-01
  • 2015-12-14
相关资源
最近更新 更多