以写信的角度类比HTTP头字段

前言

在学习HTTP协议时,头字段肯定是要了解的,但头字段种类繁多,难免弄混。用信件去类比头字段的话,可以帮助我们节省下不少学习时间,而且记忆也会更加深刻。

下面我们用写信时常用的几种类型的数据对常见头字段进行分类讨论。
  1. 地址 如果将IP比作邮件系统中具体到街道的地址的话,那Host便可以理解为报文中的门牌号。这么理解是因为IP才是我们找到服务器的依据,但是同个服务器中可能托管了很多个不同的虚拟主机(也就是域名),这个时候我们需要类似于门牌号(或者电话的分机号)的标识将服务细分到具体的域名,这样服务器才能正确地将请求路由到正确的虚拟主机处理。 例如:host: www.example.com
  2. 日期 - Date HTTP头字段和日期相关的有很多,我们先看看和写信时用的日期最相似的Date。这个Date表示的就是消息被发送的日期和时间。使用的日期和时间应该遵循RFC 7231规定的HTTP日期时间格式,例如:Fri, 23 Feb 2024 4:24:40 GMT,这是HTTP报文中标准的日期时间格式。Date字段可以用于判断一个缓存是否过期,如果一个缓存的Date字段表示它是很久之前发送的,那么缓存系统就会决定重新请求资源,而不是继续使用缓存的响应。另一个常用的场景是故障诊断,因为Date字段可以帮助开发者确定故障发生的时间,这对故障诊断和日志记录很有用。 - Last-Modified Last-Modified不同于Date,它记录的是响应资源最近更改的时间。这个字段比Date更频繁地用于缓存验证,常常配合If-Modified-Since条件请求字段来验证是否该重新请求资源。 - If-Modified-Since If-Modified-Since常用于验证缓存的时效性。这个字段的值是上一次发起客户端请求时,服务器发送的响应中包含的Last-Modified字段的值,表示的是资源最后修改的时间。如果自那个时间以来资源没有被修改过,服务器则会返回一个304 Not Modified的状态码,否则,服务器会返回修改过的资源。 - If-Unmodified-Since If-Unmodified-Since不同于If-Modified-Since,它用于实现乐观锁而非验证缓存,即只有在资源没有被其他人修改的情况下,才允许当前的请求(通常是更新或者删除)进行。
  3. 写信人 写完信后,我们有时会进行署名,以告知收信人我们的身份信息。有时我们发送报文也会想”署名”,所以HTTP报文提供了ServerUser-Agent来完成这个的目的。其中Server是响应字段,而User-Agent是请求字段。两者的值一般包含名称、版本和其他可选信息。 例如:Server: Apache/2.4.41 (Unix)
  4. 签名 出于安全性的考虑,避免有人假冒写信人的身份伪造信件,我们会对信件进行签名或者在封口盖上专属的信件印章,这些签名和印章就是我们的身份标识。类似的,有时客户端会发送报文请求有权限限制的资源,这时我们的报文就应该携带身份标识,验证通过才可以访问到资源。在报文中最常用来充当身份标识的就是AuthorizationAuthorization一般由两部分构成:验证方案和凭证。最常用的验证方案有:BasicBearerDigest。 - Basic验证方案的凭证是用户名和密码的Base64编码,例如用户名为user,密码为pass,那么凭证就是user:passBase64编码:dXNlcjpwYXNz(可以找个Base64编码器进行验证)。Basic是最简单的、也是不安全的验证方案,因为Base64编码可以轻松被破解,在不能确保通信安全的情况下,不应使用这种方案。 - Bearer验证方案的凭证是一个JWT(JSON Web Token),这也是最常用的验证方案,由于JWT较为复杂,不在此展开讨论。 - Digest验证方案的凭证包含一些使用特定算法对一些数据进行计算的哈希值,这些数据包含服务器发送回来的特殊参数的数据,常见参数有:“nonce”、“nc”、“cnonce”、“qop”等。客户端将凭证附带在Authorization字段中发送给服务器端,服务器端接收到报文后使用同样的算法重新计算哈希值,然后验证和客户端的计算值是否一致,一致则通过验证并处理请求,不一致则返回401 Unauthorized响应。
  5. 内容 和内容有关的、常见的头字段有Content-TypeContent-LengthContent-Language,内容就不继续类比了,简单粗暴,依次为:数据类型、数据长度(byte)和自然语言种类。
其他

下面是不适合用信件类比,但很常见的头字段。

  1. Connection Connection头字段用于控制网络连接。 常见的值有: keep-alive:这个值表示网络连接在处理完当前请求后,保持当前的网络连接,以便后续继续保持通讯。这种连接方式可以减少连接建立(三次握手)和断开(四次挥手)的开销,提高性能。 close:这个值表示完成当前请求的处理后,关闭网络连接。
  2. ETag ETag是一种版本标识,可提供资源的版本信息。它通常配合If-None-Match使用,用于缓存验证。
例子

最后我们分别对请求报文和响应报文举一个例子来结束文章。

  • 请求报文
代码语言:http
复制
GET /developer/article/2390462 HTTP/1.1
Host: cloud.tencent.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1.2 Safari/605.1.15
Authorization: Basic YXV0aG9yOkNvZGVTaW5nZXI=
If-Modified-Since: Fri, 23 Feb 2024 00:00:22 GMT
Connection: close
  • 响应报文
代码语言:http
复制
HTTP/1.1 200 OK
Date: Fri, 23 Feb 2024 08:47:00 GMT
Server: nginx
Last-Modified: Fri, 23 Feb 2024 08:04:15 GMT
ETag: "abc123"
Content-Type: text/html; charset=utf-8
Content-Length: 296
Content-Language: zn
Connection: close

<!DOCTYPE html>
<html>
<body>

<h1>以写信的角度类比HTTP头字段</h1>
<p>author: CodeSinger</p>

<p>如果你觉得这篇文章还不错,欢迎点赞以示支持。如果你发现任何错误,我非常欢迎你在评论区提出,我将会尽快进行修正。</p>

</body>
</html>