HTTP 面试指南

HTTP 状态码

HTTP 状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP 状态码共分为 5 种类型:

  • 1xx 信息,服务器收到请求,需要请求者继续执行操作
  • 2xx 成功,操作被成功接收并处理
  • 3xx 重定向,需要进一步的操作以完成请求
  • 4xx 客户端错误,请求包含语法错误或无法完成请求
  • 5xx 服务器错误,服务器在处理请求的过程中发生了错误

完整的 HTTP 状态码表

1xx ———— 信息状态码

状态码 状态名 状态描述
100 Continue 服务器已经接收到请求头,并且客户端应继续发送请求主体(在需要发送身体的请求的情况下:例如,POST 请求),或者如果请求已经完成,忽略这个响应。服务器必须在请求完成后向客户端发送一个最终响应。要使服务器检查请求的头部,客户端必须在其初始请求中发送 Expect: 100-continue 作为头部,并在发送正文之前接收 100 Continue 状态代码。响应代码 417 期望失败表示请求不应继续。
101 Switching Protocols 服务器已经理解了客户端的请求,并将通过 Upgrade 消息头通知客户端采用不同的协议来完成这个请求。在发送完这个响应最后的空行后,服务器将会切换到在 Upgrade 消息头中定义的那些协议。
只有在切换新的协议更有好处的时候才应该采取类似措施。例如,切换到新的 HTTP 版本(如 HTTP/2)比旧版本更有优势,或者切换到一个实时且同步的协议(如 WebSocket)以传送利用此类特性的资源。
102 Processing WebDAV 请求可能包含许多涉及文件操作的子请求,需要很长时间才能完成请求。该代码表示​​服务器已经收到并正在处理请求,但无响应可用。这样可以防止客户端超时,并假设请求丢失。

2xx ———— 成功状态码

状态码 状态名 状态描述
200 OK 请求已成功,请求所希望的响应头或数据体将随此响应返回。实际的响应将取决于所使用的请求方法。在 GET 请求中,响应将包含与请求的资源相对应的实体。在 POST 请求中,响应将包含描述或操作结果的实体。
201 Created 请求已经被实现,而且有一个新的资源已经依据请求的需要而创建,且其 URI 已经随 Location 头信息返回。假如需要的资源无法及时创建的话,应当返回’202 Accepted’。
202 Accepted 服务器已接受请求,但尚未处理。最终该请求可能会也可能不会被执行,并且可能在处理发生时被禁止。
203 Non-Authoritative Information 服务器是一个转换代理服务器(transforming proxy,例如网络加速器),以 200 OK 状态码为起源,但回应了原始响应的修改版本。
204 No Content 服务器成功处理了请求,没有返回任何内容。
205 Reset Content 服务器成功处理了请求,但没有返回任何内容。与 204 响应不同,此响应要求请求者重置文档视图。
206 Partial Content 服务器已经成功处理了部分 GET 请求。类似于 FlashGet 或者迅雷这类的 HTTP 下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。
207 Multi-Status 代表之后的消息体将是一个 XML 消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。
208 Already Reported DAV 绑定的成员已经在(多状态)响应之前的部分被列举,且未被再次包含。
226 IM Used 服务器已经满足了对资源的请求,对实体请求的一个或多个实体操作的结果表示。

3xx ———— 重定向状态码

状态码 状态名 状态描述
300 Multiple Choices 被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。用户或浏览器能够自行选择一个首选的地址进行重定向。
除非这是一个 HEAD 请求,否则该响应应当包括一个资源特性及地址的列表的实体,以便用户或浏览器从中选择最合适的重定向地址。这个实体的格式由 Content-Type 定义的格式所决定。浏览器可能根据响应的格式以及浏览器自身能力,自动作出最合适的选择。当然,RFC 2616 规范并没有规定这样的自动选择该如何进行。
如果服务器本身已经有了首选的回馈选择,那么在 Location 中应当指明这个回馈的 URI;浏览器可能会将这个 Location 值作为自动重定向的地址。此外,除非额外指定,否则这个响应也是可缓存的。
301 Moved Permanently 被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。如果可能,拥有链接编辑功能的客户端应当自动把请求的地址修改为从服务器反馈回来的地址。除非额外指定,否则这个响应也是可缓存的。
新的永久性的 URI 应当在响应的 Location 域中返回。除非这是一个 HEAD 请求,否则响应的实体中应当包含指向新的 URI 的超链接及简短说明。
如果这不是一个 GET 或者 HEAD 请求,因此浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。
注意:对于某些使用 HTTP/1.0 协议的浏览器,当它们发送的 POST 请求得到了一个 301 响应的话,接下来的重定向请求将会变成 GET 方式。
302 Found 要求客户端执行临时重定向(原始描述短语为“Moved Temporarily”)。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在 Cache-Control 或 Expires 中进行了指定的情况下,这个响应才是可缓存的。
新的临时性的 URI 应当在响应的 Location 域中返回。除非这是一个 HEAD 请求,否则响应的实体中应当包含指向新的 URI 的超链接及简短说明。
如果这不是一个 GET 或者 HEAD 请求,那么浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。
注意:虽然 RFC 1945 和 RFC 2068 规范不允许客户端在重定向时改变请求的方法,但是很多现存的浏览器将 302 响应视作为 303 响应,并且使用 GET 方式访问在 Location 中规定的 URI,而无视原先请求的方法。因此状态码 303 和 307 被添加了进来,用以明确服务器期待客户端进行何种反应。
303 See Other 对应当前请求的响应可以在另一个 URI 上被找到,当响应于 POST(或 PUT / DELETE)接收到响应时,客户端应该假定服务器已经收到数据,并且应该使用单独的 GET 消息发出重定向。这个方法的存在主要是为了允许由脚本激活的 POST 请求输出重定向到一个新的资源。这个新的 URI 不是原始资源的替代引用。同时,303 响应禁止被缓存。当然,第二个请求(重定向)可能被缓存。
新的 URI 应当在响应的 Location 域中返回。除非这是一个 HEAD 请求,否则响应的实体中应当包含指向新的 URI 的超链接及简短说明。
注意:许多 HTTP/1.1 版以前的浏览器不能正确理解 303 状态。如果需要考虑与这些浏览器之间的互动,302 状态码应该可以胜任,因为大多数的浏览器处理 302 响应时的方式恰恰就是上述规范要求客户端处理 303 响应时应当做的。
304 Not Modified 表示资源未被修改,因为请求头指定的版本 If-Modified-Since 或 If-None-Match。在这种情况下,由于客户端仍然具有以前下载的副本,因此不需要重新传输资源。
305 Use Proxy 被请求的资源必须通过指定的代理才能被访问。Location 域中将给出指定的代理所在的 URI 信息,接收者需要重复发送一个单独的请求,通过这个代理才能访问相应资源。只有原始服务器才能创建 305 响应。许多 HTTP 客户端(像是 Mozilla 和 Internet Explorer)都没有正确处理这种状态代码的响应,主要是出于安全考虑。
注意:RFC 2068 中没有明确 305 响应是为了重定向一个单独的请求,而且只能被原始服务器建立。忽视这些限制可能导致严重的安全后果。
306 Switch Proxy 在最新版的规范中,306 状态码已经不再被使用。最初是指“后续请求应使用指定的代理”。
307 Temporary Redirect 在这种情况下,请求应该与另一个 URI 重复,但后续的请求应仍使用原始的 URI。 与 302 相反,当重新发出原始请求时,不允许更改请求方法。 例如,应该使用另一个 POST 请求来重复 POST 请求。
308 Permanent Redirect 请求和所有将来的请求应该使用另一个 URI 重复。 307 和 308 重复 302 和 301 的行为,但不允许 HTTP 方法更改。 例如,将表单提交给永久重定向的资源可能会顺利进行。

4xx ———— 客户端错误状态码

状态码 状态名 状态描述
400 Bad Request 由于明显的客户端错误(例如,格式错误的请求语法,太大的大小,无效的请求消息或欺骗性路由请求),服务器不能或不会处理该请求。
401 Unauthorized 类似于 403 Forbidden,401 语义即“未认证”,即用户没有必要的凭据。该状态码表示当前请求需要用户验证。该响应必须包含一个适用于被请求资源的 WWW-Authenticate 信息头用以询问用户信息。客户端可以重复提交一个包含恰当的 Authorization 头信息的请求。如果当前请求已经包含了 Authorization 证书,那么 401 响应代表着服务器验证已经拒绝了那些证书。如果 401 响应包含了与前一个响应相同的身份验证询问,且浏览器已经至少尝试了一次验证,那么浏览器应当向用户展示响应中包含的实体信息,因为这个实体信息中可能包含了相关诊断信息。
注意:当网站(通常是网站域名)禁止 IP 地址时,有些网站状态码显示的 401,表示该特定地址被拒绝访问网站。
402 Payment Required 该状态码是为了将来可能的需求而预留的。该状态码最初的意图可能被用作某种形式的数字现金或在线支付方案的一部分,但几乎没有哪家服务商使用,而且这个状态码通常不被使用。如果特定开发人员已超过请求的每日限制,Google Developers API 会使用此状态码。
403 Forbidden 服务器已经理解请求,但是拒绝执行它。与 401 响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。如果这不是一个 HEAD 请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个 404 响应,假如它不希望让客户端获得任何信息。
404 Not Found 请求失败,请求所希望得到的资源未被在服务器上发现,但允许用户的后续请求。没有信息能够告诉用户这个状况到底是暂时的还是永久的。假如服务器知道情况的话,应当使用 410 状态码来告知旧资源因为某些内部的配置机制问题,已经永久的不可用,而且没有任何可以跳转的地址。404 这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。
405 Method Not Allowed 请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个 Allow 头信息用以表示出当前资源能够接受的请求方法的列表。例如,需要通过 POST 呈现数据的表单上的 GET 请求,或只读资源上的 PUT 请求。
鉴于 PUT,DELETE 方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法,对于此类请求均会返回 405 错误。
406 Not Acceptable 请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体,该请求不可接受。
除非这是一个 HEAD 请求,否则该响应就应当返回一个包含可以让用户或者浏览器从中选择最合适的实体特性以及地址列表的实体。实体的格式由 Content-Type 头中定义的媒体类型决定。浏览器可以根据格式及自身能力自行作出最佳选择。但是,规范中并没有定义任何作出此类自动选择的标准。
407 Proxy Authentication Required 与 401 响应类似,只不过客户端必须在代理服务器上进行身份验证。代理服务器必须返回一个 Proxy-Authenticate 用以进行身份询问。客户端可以返回一个 Proxy-Authorization 信息头用以验证。
408 Request Timeout 请求超时。根据 HTTP 规范,客户端没有在服务器预备等待的时间内完成一个请求的发送,客户端可以随时再次提交这一请求而无需进行任何更改。
409 Conflict 表示因为请求存在冲突无法处理该请求,例如多个同步更新之间的编辑冲突。
410 Gone 表示所请求的资源不再可用,将不再可用。当资源被有意地删除并且资源应被清除时,应该使用这个。在收到 410 状态码后,用户应停止再次请求资源。但大多数服务端不会使用此状态码,而是直接使用 404 状态码。
411 Length Required 服务器拒绝在没有定义 Content-Length 头的情况下接受请求。在添加了表明请求消息体长度的有效 Content-Length 头之后,客户端可以再次提交该请求。
412 Precondition Failed 服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。这个状态码允许客户端在获取资源时在请求的元信息(请求头字段数据)中设置先决条件,以此避免该请求方法被应用到其希望的内容以外的资源上。
413 Request Entity Too Large 前称“Request Entity Too Large”,表示服务器拒绝处理当前请求,因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。此种情况下,服务器可以关闭连接以免客户端继续发送此请求。
如果这个状况是临时的,服务器应当返回一个 Retry-After 的响应头,以告知客户端可以在多少时间以后重新尝试。
414 Request-URI Too Long 前称“Request-URI Too Long”,表示请求的 URI 长度超过了服务器能够解释的长度,因此服务器拒绝对该请求提供服务。通常将太多数据的结果编码为 GET 请求的查询字符串,在这种情况下,应将其转换为 POST 请求。这比较少见,通常的情况包括:
本应使用 POST 方法的表单提交变成了 GET 方法,导致查询字符串过长。
重定向 URI“黑洞”,例如每次重定向把旧的 URI 作为新的 URI 的一部分,导致在若干次重定向后 URI 超长。
客户端正在尝试利用某些服务器中存在的安全漏洞攻击服务器。这类服务器使用固定长度的缓冲读取或操作请求的 URI,当 GET 后的参数超过某个数值后,可能会产生缓冲区溢出,导致任意代码被执行。没有此类漏洞的服务器,应当返回 414 状态码。
415 Unsupported Media Type 对于当前请求的方法和所请求的资源,请求中提交的互联网媒体类型并不是服务器中所支持的格式,因此请求被拒绝。例如,客户端将图像上传格式为 svg,但服务器要求图像使用上传格式为 jpg。
416 Requested Range Not Satisfiable 前称“Requested Range Not Satisfiable”。客户端已经要求文件的一部分(Byte serving),但服务器不能提供该部分。例如,如果客户端要求文件的一部分超出文件尾端。
417 Expectation Failed 在请求头 Expect 中指定的预期内容无法被服务器满足,或者这个服务器是一个代理服显的证据证明在当前路由的下一个节点上,Expect 的内容无法被满足。
418 I’m a teapot 本操作码是在 1998 年作为 IETF 的传统愚人节笑话, 在 RFC 2324 超文本咖啡壶控制协议’中定义的,并不需要在真实的 HTTP 服务器中定义。当一个控制茶壶的 HTCPCP 收到 BREW 或 POST 指令要求其煮咖啡时应当回传此错误。这个 HTTP 状态码在某些网站(包括 Google.com)与项目(如 Node.js、ASP.NET 和 Go 语言)中用作彩蛋。
420 Enhance Your Caim Twitter Search 与 Trends API 在客户端被限速的情况下返回。
421 Misdirected Request 该请求针对的是无法产生响应的服务器(例如因为连接重用)。
422 Unprocessable Entity 请求格式正确,但是由于含有语义错误,无法响应。
423 Locked 当前资源被锁定。
424 Failed Dependency 由于之前的某个请求发生的错误,导致当前请求失败,例如 PROPPATCH。
425 Unordered Collection 在 WebDAV Advanced Collections Protocol 中定义,但 Web Distributed Authoring and Versioning (WebDAV) Ordered Collections Protocol 中并不存在。
426 Upgrade Required 客户端应当切换到 TLS/1.0,并在 HTTP/1.1 Upgrade header 中给出。
428 Precondition Required 原服务器要求该请求满足一定条件。这是为了防止“‘未更新’问题,即客户端读取(GET)一个资源的状态,更改它,并将它写(PUT)回服务器,但这期间第三方已经在服务器上更改了该资源的状态,因此导致了冲突。”
429 Too Many Requests 用户在给定的时间内发送了太多的请求。旨在用于网络限速。
431 Request Header Fields Too Large 服务器不愿处理请求,因为一个或多个头字段过大。
444 No Response Nginx 上 HTTP 服务器扩展。服务器不向客户端返回任何信息,并关闭连接(有助于阻止恶意软件)。
450 Blocked by Windows Parental Controls 这是一个由 Windows 家庭控制(Microsoft)HTTP 阻止的 450 状态代码的示例,用于信息和测试。
451 Unavailable For Legal Reasons 该访问因法律的要求而被拒绝,由 IETF 在 2015 核准后新增加。
494 Request Header Too Large 在错误代码 431 提出之前 Nginx 上使用的扩展 HTTP 代码。

5xx ———— 服务器错误状态码

状态码 状态名 状态描述
500 Internal Server Error 通用错误消息,服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。没有给出具体错误信息。
501 Not Implemented 服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。(例如,网络服务 API 的新功能)
502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。
503 Service Unavailable 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是暂时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个 Retry-After 头用以标明这个延迟时间。如果没有给出这个 Retry-After 信息,那么客户端应当以处理 500 响应的方式处理它。
504 Gateway Timeout 作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI 标识出的服务器,例如 HTTP、FTP、LDAP)或者辅助服务器(例如 DNS)收到响应。
注意:某些代理服务器在 DNS 查询超时时会返回 400 或者 500 错误。
505 HTTP Version Not Supported 服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本。这暗示着服务器不能或不愿使用与客户端相同的版本。响应中应当包含一个描述了为何版本不被支持以及服务器支持哪些协议的实体。
506 Variant Also Negotiates 由《透明内容协商协议》(RFC 2295)扩展,代表服务器存在内部配置错误,被请求的协商变元资源被配置为在透明内容协商中使用自己,因此在一个协商处理中不是一个合适的重点。
507 Insufficient Storage 服务器无法存储完成请求所必须的内容。这个状况被认为是临时的。
508 Loop Detected 服务器在处理请求时陷入死循环。(可代替 208 状态码)
510 Not Extended 获取资源所需要的策略并没有被满足。
511 Network Authentication Required 客户端需要进行身份验证才能获得网络访问权限,旨在限制用户群访问特定网络。(例如连接 WiFi 热点时的强制网络门户)

HTTP 头部字段

HTTP 头字段根据实际用途被分为以下 4 种类型:

  • 通用头字段(英语:General Header Fields)
  • 请求头字段(英语:Request Header Fields)
  • 响应头字段(英语:Response Header Fields)
  • 实体头字段(英语:Entity Header Fields)

HTTP 通用头字段

一、Cache-Control

通过这个首部字段可以操作缓存的工作机制。它的参数是可选的,多个指令之间通过 “,” 分隔,例如:

1
Cache-Control: private, max-age=0, no-cache

缓存请求指令:

指令 参数 说明
no-cache 强制向源服务器再次验证
no-store 不缓存请求或响应的任何内容
max-age=[秒] 必需 响应的最大 Age 值
max-stale=[秒] 可省略 接收已过期的响应
min-fresh=[秒] 必需 期望在指定时间内的响应仍有效
no-transform 代理不可更改媒体类型
only-if-cached 从缓存获取资源
cache-extension - 新指令标记

缓存响应指令:

指令 参数 说明
public 可向任意方提供响应的缓存
private 可省略 仅向特定用户返回响应
no-cache 可省略 缓存前必须确认其有效性
no-store 不缓存请求或响应的任何内容
no-transform 代理不可更改媒体类型
must-revalidate 可缓存但必须向源服务器进行确认
proxy-revalidate 要求中间缓存服务器对缓存的响应有效性再进行确认
max-age=[秒] 必需 响应的最大 Age 值
s-macage=[秒] 必需 公共缓存服务器响应的最大 Age 值
cache-extension - 新指令标记
  • public 指令
    1
    Cache-Control: public

此指令表示其它用户也可利用缓存。

  • private 指令
    1
    Cache-Control: private

此指令表示响应只以特定的用户作为对象,与 public 的行为正好相反。

  • no-cache 指令
    1
    Cache-Control: no-cache

此指令的目的是为了防止从缓存中返回 过期 的资源。

  • no-store 指令
    1
    Cache-Control: no-store

此指令规定不能在本地存储请求或者响应的任何一部分。

从字面意思上很容易把 no-cache 误解成为不缓存,实际它代表的是不缓存过期的资源,缓存会向源服务器进行有效期确认后处理资源,也许称为 do-not-serve-from-cache-without-revalidation 更合适。no-store 才是真正地不进行缓存,请注意它们的区别。

  • max-age 指令
    1
    Cache-Control: maxage=604800(单位:秒)

当客户端发送的请求中包含 max-age 指令时,如果判定缓存资源的缓存时间数值比指定时间的数值更小,那么客户端就接收缓存的资源。当 max-age 值为 0,缓存服务器需要将请求转发给源服务器。

当服务器返回的响应中包含 max-age 指令时,缓存服务器将不对资源的有效性再作确认,它的数值代表了缓存的最长时间。如果同时存在 Expires 字段,会优选处理 max-age 指令,而忽略掉 Expires 字段。

  • s-maxage 指令
    1
    Cache-Control: s-maxage=604800(单位:秒)

它的作用和 max-age 指令相同,不同点有两个:

  1. 此指令只适用于供多位用户使用的公共缓存服务器,对于向同一用户重复返回响应的服务器来说,这个指令是没有用的。
  2. 当使用此指令后,会直接忽略对 Expires、max-age 指令的处理。
  • min-fresh 指令
    1
    Cache-Control: min-fresh=60(单位:秒)

此指令要求缓存服务器返回还未过指定时间的缓存资源。

  • max-stale 指令
    1
    Cache-Control: max-stale=3600(单位:秒)

此指令表示即使缓存资源过期也照常接收。如果未指定参数值,那么无论经过多久,客户端都会接收响应。如果指定了具体值,那么即使过期,只要没有超过 max-stale 指定的时间内,客户端依然会接收。

  • only-if-cached 指令
    1
    Cache-Control: only-if-cached

此指令表示客户端仅在缓存服务器本直缓存了目标资源的情况下,才会要求其返回。该指令不要求缓存服务器重新加载响应,也不会再次确认资源有效性。若缓存服务器无响应,则返回 504 Gateway Timeout。

  • must-revalidate 指令
    1
    Cache-Control: must-revalidate

此指令表示代理服务器会向源服务器再次验证即将返回的响应缓存目前是否仍然有效。若代理服务器无法从源服务器获取有效资源的话,应该给客户端返回 504 Gateway Timeout。使用此指令之后,max-stale 指令会被忽略。

  • proxy-revalidate 指令
    1
    Cache-Control: proxy-revalidate

此指令表示所有的缓存服务器在返回响应之前必须再次验证缓存的有效性。

  • no-transform 指令
    1
    Cache-Control: no-transform

此指令表示无论是在请求或者响应中,缓存都不能改变实体主体的缓存类型。

  • Cache-Control 扩展

cache-extension token

1
Cache-Control: private, community="UCI"

通过此标记,可以扩展 Cache-Control 的字段指令。如上例,就扩展了 community 这个指令。如果目标服务器不理解这个指令,就会直接忽略。

二、connection

connection 首部字段有两个作用:

  1. 控制不再转发给代理的首部字段

    1
    connection: 不再转发的首部字段名
  2. 管理持久连接

HTTP/1.1 默认都是持久连接的,客户端可以在持久连接上连续发送请求。当服务器明确想断开连接时,则指定首部字段值为 close:

1
Connection: close

HTTP/1.1 之前的版本如果想维持持久连接,则需要明确指定字段值为 Keep-Alive:

1
Connection: Keep-Alive

三、Date

首部字段 Date 表明创建 HTTP 报文的日期和时间。

四、Pragma

首部字段 Pragma 是 HTTP/1.1 之前版本的遗留字段,只用在客户端请求中。作用是要求所有的中间服务器不返回缓存资源。因此为了兼容 HTTP/1.1 之前的版本,在发送请求时会包含两个首部字段:

1
2
Cache-Control: no-cache
Pragma: no-cache

五、Trailer

首部字段 Traliler 事先说明了报文主体后记录了哪些首部和字段,主要是应用在分块传输编码时。

六、Transfer-Encoding

首部字段 Transfer-Encoding 规定了传输报文主体时采用的编码方式,仅对分块传输编码有效。

七、Upgrade

首部字段 Upgrade 用于检测 HTTP 协议及其它协议是否可用更高的版本进行通信,其参数可以用来指定一个完全不同的通信协议。

八、Via

首部字段 Via 是为了追踪客户端与服务器之间的请求和响应报文的传输路径。报文经过代理或者网关时,会先在首部 Via 中附加服务器的信息,然后再进行转发。

九、Warning

首部字段 Warning 通常会告知用户一些与缓存相关的问题警告。

HTTP 请求头字段

请求首部字段是从客户端往服务器发送请求报文中所使用的字段,用于补充请求的附加信息、客户端信息、对响应内容相关的优先级等内容。

一、Accept

首部字段 Accept 通知服务器,用户代理能够处理的媒体类型及媒体类型的相对优先级。可使用 type/subtype 这种形式,一次指定多种媒体类型。

1
Accept: text/plain; q=0.3, text/html

使用 q= 来表示媒体类型的优先级,用分号进行分隔。权重 q 值的范围是 0~1(可精确到小数点后 3 位)。不指 q 值时,默认权重为 q=1.0。所以,浏览器会优先返回权重值最高的媒体类型。

二、Accept-Charset

首部字段 Accept-Charset 用来告知服务器用户代理支持的字符集及字符集的优先顺序。可一次性指定多种字符集,使用权重 q 来表示相对优先级顺序。

1
Accept-Charset: iso-8859-5, unicode-1-1; q=0.8

三、Accept-Encoding

首部字段 Accept-Encoding 用来告知服务器用户代理支持的内容编码。可一次性指定多种,使用权重 q 表示相对优先级顺序。也可使用星号(*)作为通配符,指定任意的编码格式。常用的几种编码:gzip、compress、deflate、identity。

四、Accept-Language

首部字段 Accept-Language 用来告知服务器用户代理能够处理的自然语言集(指中文或英文等)。可指定多个自然语言集,使用权重 q 来表示相对优先级顺序。

1
Accept-Language: zh-cn,zh; q=0.7, en-us,en; q=0.3

五、Authorization

首部字段 Authorization 用来告知服务器用户代理的认证信息(证书值)。

1
Authorization: Basic dWVub3NlbjpwYXNzd29yZA==

六、Expect

首部字段 Expect 用来告知服务器期望出现的某种特定行为。如果服务器无法理解发生错误时,应该返回状态码 417 Expectation Failed.

七、From

首部字段 From 用来告知服务器使用用户代理的用户的电子邮件地址。

1
From: info@jd.com

八、Host

首部字段 Host 告知服务器请求的资源所处的互联网主机名和端口号。它是 HTTP/1.1 规范内唯一一个必须被包含在请求内的首部字段。

1
Host: www.jd.com

九、If-Match

形如 If-Match 的请求首部字段,都可称为条件请求。只有当 If-Match 的字段值跟 Etag 值匹配一致时,服务器才会执行请求。如果指定星号(*)值,则服务器会忽略 Etag 值,只要资源存在就会处理请求。

1
If-Match: "123456"

十、If-Modified-Since

它会告知服务器若 If-Modified-Since 的字段值早于资源的更新时间,则希望能处理此请求。否则,服务器应该返回状态码 304 Not Modified。一般用于确认代理或者客户端本地缓存资源的有效性。

1
If-Modified-Since: Thu, 15 Apr 2004 00:00:00 GMT

十一、If-None-Match

此首部字段用于告知服务器,当它的字段值与 Etag 不一致时,希望服务器处理该请求。

十二、If-Range

此首部字段用于告知服务器,当它的字段值与请求资源的 Etag 值或时间相一致时,则作为范围请求处理。反之,则返回全体资源。

1
If-Range: "123456"

十三、If-Unmodified-Since

此首部字段用于告知服务器,指定的请求资源只有在字段值指定的日期之后,未发生更新的情况下,才能处理请求。否则,服务器应该返回状态码 412 Precondition Failed。

1
If-Unmodified-Since: Thu, 03 Jul 2012 00:00:00 GMT

十四、Max-Forwards

通过 TRACE 方法或者 OPTIONS 方法,发送包含此首部字段的请求时,字段值以十进制整数形式指定可经过的服务器最大数目。

1
Max-Forwards: 10

十五、Proxy-Authorization

此首部字段用于告知代理服务器所需要的认证信息。这个认证只发生于客户端与代理服务器之间。客户端与服务器之间的认证需要使用首部字段 Authorization。

1
Proxy-Authorization: Basic dGlwOjkpNLAGfFY5

十六、Range

此首部字段用于告知服务器获取部分资源的范围请求,例如以下示例就是获取从第 5001 字节至第 10000 字节的资源。服务器处理请求之后返回的状态码应该为 206 Partial Content。无法处理该请求时,应该返回状态码 200 OK 以及全部资源。

1
Range: 5001-10000

十七、Referer

此首部字段会告知服务器请求的原始资源 URI。但是,直接在浏览器地址栏输入 URI 或者出于安全考虑时,也可以不发送该首部字段。另外,Referer 的正确拼写应该是 Referrer,不知为何,这个错误一直延续至今。

1
Referer: http://www.jd.com

十八、TE

此首部字段用于告知服务器客户端能够处理响应的传输编码方式及相对优先级。它和首部字段 Accept-Encoding 的功能很相似,但是用于传输编码。

1
TE: gzip, deflate;q=0.5

十九、User-Agent

此首部字段会将创建请求的浏览器和用户代理名称等信息传达给服务器。

1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/⇒20100101 Firefox/13.0.1

HTTP 响应头字段

响应首部字段是由服务器端向客户端返回响应报文中所使用的字段,用过补充响应的附加信息、服务器信息,以及对客户端的附加要求等信息。

一、Accept-Ranges

此首部字段用于告知客户端服务器是否能处理范围请求。如果能处理返回的值为 bytes,否则返回的值为 none。

1
Accept-Ranges: bytes

二、Age

此首部字段用于告知客户端,服务器在多久前创建了响应,单位为秒。若是缓存服务器,则是指缓存后的响应再次发起认证到认证完成的时间值。代理创建响应时必须带上此首部字段。

1
Age: 600

三、ETag

它是一种可将资源以字符串形式做唯一标识的方式。服务器会为每份资源分配对应的 ETag 值。资源更新时,ETag 值也会更新。生成 ETag 值的算法由服务器决定。ETag 值分为两种:

  • 强 ETag 值

不认实体发生多么细微的变化都会改变其值。

1
ETag: "usagi-1234"

  • 弱 ETag 值

只用于提示资源是否相同,只有资源发生了根本改变,产生差异时才会改变 ETag 值,而且在字符值最开始处附加 W/。

1
ETag: W/"usagi-1234"

四、Location

几乎所有的浏览器在接收到包含首部字段 Location 的响应后,都会强制性地尝试进行资源重定向。

1
Location: http://www.jd.com

五、Proxy-Authenticate

把由代理服务器所要求的认证信息发送给客户端。

1
Proxy-Authenticate: Basic realm="Usagidesign Auth"

六、Retry-After

此首部字段告知客户端应该在多久之后再次发送请求。主要是配合状态码 503 Service Unavailable 或者 3xx Redirect。可以指定具体的时间值,也可以是创建响应后的秒数。

1
Retry-After: 120

七、Server

此首部字段告知客户端当前服务器上安装的 HTTP 服务器应用程序的信息。不仅仅有应用程序的名称,还有可能包括版本号和安装时启用的可选项。

1
2
Server: Apache/2.2.17 (Unix)
Server: Apache/2.2.6 (Unix) PHP/5.2.5

八、Vary

此首部字段可对缓存进行控制。从代理服务器收到源服务器返回包含 Vary 的响应之后,若要再进行缓存,仅对请求中含有相同 Vary 字段值的请求返回缓存。即使请求相同的资源,但是 Vary 指定的首部字段值不相同,也要必须从源服务器重新获取资源。

1
Vary: Accept-Language

九、WWW-Authenticate

此首部字段用于 HTTP 访问认证。

1
WWW-Authenticate: Basic realm="Usagidesign Auth"

HTTP 实体头字段

实体首部字体是包含在请求报文和响应报文中的实体部分所使用的首部,用于补充内容的更新时间等与实体相关的信息。

一、Allow

此首部字段用于告知客户端能够支持 Request-URI 指定资源的 HTTP 方法。当服务器收到不支持的 HTTP 方法时,会返回状态码 405 Method Not Allowed,并且还会把所有支持的 HTTP 方法写入首部字段 Allow 后返回。

1
Allow: GET, HEAD

二、Content-Encoding

此首部字段用于告知客户端服务器对实体的主体部分选用的内容编码方式。

1
Content-Encoding: gzip

三、Content-Language

此首部字体用于告知客户端,实体主体使用的自然语言(指中文或者英文等)。

1
Content-Language: zh-CN

四、Content-Length

此首部字段表明了实体主体部分的大小(单位是字节)。对实体主体进行内容编码传输时,不能再使用 Content-Length 首部字段。

1
Content-Length: 15000

五、Content-Location

此首部字段表示的是报文主体返回资源对应的 URI。

1
Content-Location: http://www.jd.com/index.html

六、Content-MD5

此首部字段是一串由 MD5 算法生成的值,其目的在于检查报文主体在传输过程中是否保持完整。客户端会对接收的报文主体执行相同的 MD5 算法,然后与此首部字段值进行比较。

1
Content-MD5: OGFkZDUwNGVhNGY3N2MxMDIwZmQ4NTBmY2IyTY==

七、Content-Range

作为返回响应时使用此首部字段,能告知客户端返回的实体的哪个部分符合范围请求。字段值以字节为单位。

1
Content-Range: bytes 5001-10000/10000

八、Content-Type

此首部字段说明了实体主体内对象的媒体类型。字段值用 type/subtype 形式赋值。

1
Content-Type: text/html; charset=UTF-8

九、Expires

此首部字段用于告知客户端缓存资源失效的日期。

1
Expires: Wed, 04 Jul 2012 08:26:05 GMT

十、Last-Modified

此首部字段用来指明资源的最后修改时间。

1
Last-Modified: Wed, 23 May 2012 09:59:55 GMT

HTTP 请求过程

  1. 域名解析
  2. 与目标 IP 建立起基于 TCP 的 HTTP 连接
  3. 传输请求数据
  4. 服务器收到请求数据
  5. 服务器执行对应的 CGI 程序进行处理
  6. 服务器把处理结果通过之前建立起来的 HTTP 连接响应给客户端
  7. 客户端将响应结果处理后渲染给用户,同时服务器关闭与客户端建立的连接

HTTP 2.0 的特性

一、HTTP 2.0:改进传输性能

HTTP 2.0 的主要目标是改进传输性能,实现低延迟和高吞吐量。从另一方面看,HTTP 的高层协议语义并不会因为这次版本升级而受影响。所有 HTTP 首部、值,以及它们的使用场景都不会变。

现有的任何网站和应用,无需做任何修改都可以在 HTTP 2.0 上跑起来。不用为了利用 HTTP 2.0 的好处而修改标记。HTTP 服务器必须运行 HTTP 2.0 协议,但大部分用户都不会因此而受到影响。

二、HTTP2.0 历史及其与 SPDY 的渊源

SPDY 是谷歌开发的一个实验性协议,于 2009 年年中发布,主要目标是通过解决 HTTP 1.1 中广为人知的一些性能限制,来减少网页的加载延迟

SPDY 协议设定的目标

  • 页面加载时间(PLT,Page • Load Time)降低 50%;
  • 无需网站作者修改任何内容;
  • 把部署复杂性降至最低,无需变更网络基础设施;
  • 与开源社区合作开发这个新协议;
  • 收集真实性能数据,验证这个实验性协议是否有效。

    Alt text

注:为了达到降低 50% 页面加载时间的目标,SPDY 引入了一个新的二进制分帧数据层,以实现多向请求和响应、优先次序、最小化及消除不必要的网络延迟,目的是更有效地利用底层 TCP 连接;

HTTP-WG(HTTP Working Group)在 2012 年初把 HTTP 2.0 提到了议事日程,吸取 SPDY 的经验教训,并在此基础上制定官方标准

三、HTTP2.0 深入探究

HTTP/2.0 应该满足如下条件:

  • 相对于使用 TCP 的 HTTP 1.1,• 用户在大多数情况下的感知延迟要有实质上、可度量的改进;
  • 解决 HTTP 中的 “队首阻塞” 问题;
  • 并行操作无需与服务器建立多个连接,从而改进 TCP 的利用率,特别是拥塞控制方面;
  • 保持 HTTP 1.1 的语义,利用现有文档,包括(但不限于)HTTP 方法、状态码、URI,以及首部字段;
  • 明确规定 HTTP 2.0 如何与 HTTP 1.x 互操作,特别是在中间介质上;
  • 明确指出所有新的可扩展机制以及适当的扩展策略。

HTTP 2.0 致力于突破上一代标准众所周知的性能限制,但它也是对之前 1.x 标准的扩展,而非替代。之所以要递增一个大版本到 2.0,主要是因为它改变了客户端与服务器之间交换数据的方式,HTTP 2.0 增加了新的二进制分帧数据层

四、HTTP2.0 设计和技术目标

HTTP/2.0 通过支持首部字段压缩和在同一连接上发送多个并发消息,让应用更有效地利用网络资源,减少感知的延迟时间。而且,它还支持服务器到客户端的主动推送机制。

  • 二进制分帧层

    • HTTP 2.0 二进制分帧层,封装 HTTP 消息并在客户端与服务器之间传输

    Alt text

    • HTTP2.0 将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码。

    • 注:HTTPS 是二进制分帧的另一个典型示例:所有 HTTP 消息都以透明的方式为我们编码和解码,不必对应用进行任何修改。HTTP2.0 工作原理有点类似

  • 流、消息和帧

    • 流:流是连接中的一个虚拟信道,可以承载双向的消息;每个流都有一个唯一的整数标识符(1、2…N);
    • 消息:是指逻辑上的 HTTP 消息,比如请求、响应等,由一或多个帧组成。
    • 帧:HTTP 2.0 通信的最小单位,每个帧包含帧首部,至少也会标识出当前帧所属的流,承载着特定类型的数据,如 HTTP 首部、负荷,等等

    Alt text

    • HTTP 2.0 的所有帧都采用二进制编码,所有首部数据都会被压缩。
    • 所有通信都在一个 TCP 连接上完成。
    • HTTP 2.0 把 HTTP 协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息。相应地,很多流可以并行地在同一个 TCP 连接上交换消息
  • 多向请求与响应

    • HTTP 2.0 中新的二进制分帧层突破了这些限制,实现了多向请求和响应:客户端和服务器可以把 HTTP 消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把它们重新组合起来

      Alt text

    • 图中包含了同一个连接上多个传输中的数据流:客户端正在向服务器传输一个 DATA 帧(stream 5),与此同时,服务器正向客户端乱序发送 stream 1 和 stream 3 的一系列帧。此时,一个连接上有 3 个请求 / 响应并行交换!

    • 把 HTTP 消息分解为独立的帧,交错发送,然后在另一端重新组装是 HTTP 2.0 最重要的一项增强。这个机制会在整个 Web 技术栈中引发一系列连锁反应,从而带来巨大的性能提升。

    1
    2
    3
    4
    5
    6

    * 可以并行交错地发送请求,请求之间互不影响;
    * 可以并行交错地发送响应,响应之间互不干扰;
    * 只使用一个连接即可并行发送多个请求和响应;
    * 消除不必要的延迟,从而减少页面加载的时间;
    * 不必再为绕过 HTTP 1.x 限制而多做很多工作;
    • HTTP 2.0 的二进制分帧机制解决了 HTTP 1.x 中存在的队首阻塞问题,也消除了并行处理和发送请求及响应时对多个连接的依赖。
  • 请求优先级

    • 把 HTTP 消息分解为很多独立的帧之后,就可以通过优化这些帧的交错和传输顺序,每个流都可以带有一个 31 比特的优先值:0 表示最高优先级;2 的 31 次方 - 1 表示最低优先级。
    • 服务器可以根据流的优先级,控制资源分配(CPU、内存、带宽),而在响应数据准备好之后,优先将最高优先级的帧发送给客户端。
    • HTTP 2.0 一举解决了所有这些低效的问题:浏览器可以在发现资源时立即分派请求,指定每个流的优先级,让服务器决定最优的响应次序。这样请求就不必排队了,既节省了时间,也最大限度地利用了每个连接。
  • 每个来源一个连接

    • 有了新的分帧机制后,HTTP 2.0 不再依赖多个 TCP 连接去实现多流并行了。每个数据流都拆分成很多帧,而这些帧可以交错,还可以分别优先级。HTTP 2.0 连接都是持久化的,而且客户端与服务器之间也只需要一个连接即可。
      • 实验表明,客户端使用更少的连接肯定可以降低延迟时间。HTTP 2.0 发送的总分组数量比 HTTP 差不多要少 40%。
      • 大多数 HTTP 连接的时间都很短,而且是突发性的,但 TCP 只在长时间连接传输大块数据时效率才最高。HTTP 2.0 通过让所有数据流共用同一个连接,可以更有效地使用 TCP 连接。
  • 流量控制

    • HTTP 2.0 为数据流和连接的流量控制提供了一个简单的机制:
      • 流量控制基于每一跳进行,而非端到端的控制;
      • 流量控制基于窗口更新帧进行,即接收方广播自己准备接收某个数据流的多少字节,以及对整个连接要接收多少字节;
      • 流量控制窗口大小通过 WINDOW_UPDATE 帧更新,这个字段指定了流 ID 和窗口大小递增值;
      • 流量控制有方向性,即接收方可能根据自己的情况为每个流乃至整个连接设置任意窗口大小;
      • 流量控制可以由接收方禁用,包括针对个别的流和针对整个连接。
  • 服务器推送

    • HTTP 2.0 新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。服务器向客户端推送资源无需客户端明确地请求。

      Alt text

    • HTTP 2.0 连接后,客户端与服务器交换 SETTINGS 帧,借此可以限定双向并发的流的最大数量。因此,客户端可以限定推送流的数量,或者通过把这个值设置为 0 而完全禁用服务器推送。

    • 所有推送的资源都遵守同源策略。换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行。

    • PUSH_PROMISE:所有服务器推送流都由 PUSH_PROMISE 发端,服务器向客户端发出的有意推送所述资源的信号。客户端接收到 PUSH_PROMISE 帧之后,可以视自身需求选择拒绝这个流

    • 几点限制:

      • 服务器必须遵循请求 - 响应的循环,只能借着对请求的响应推送资源
      • PUSH_PROMISE 帧必须在返回响应之前发送,以免客户端出现竞态条件。
  • 首部压缩(HPACK 压缩算法,一边用 index mapping table 压缩,一边编码,这个 table 由静态表和动态表组成)

    • http2.0 会压缩首部元数据:在客户端和服务器端使用 “首部表” 来跟踪和存储之前发送的键值对,对于相同的数据,不再通过每次请求和响应发送;“首部表”在 http2.0 的连接存续期内始终存在,由客户端和服务器共同渐进地更新;每个新的首部键值对要么追加到当前表的末尾,要么替换表中之前的值。

    • http2.0 首部差异化传输

      Alt text

      • 请求与响应首部的定义在 HTTP2.0 中基本没有改变,只是所有首部键必须全部小写,而且请求行要独立为 :method、:scheme、:host、:path 这些键值对。
  • 有效的 HTTP2.0 升级与发现

    • 大多数现代浏览器都内置有高效的后台升级机制,支持 HTTP2.0 的客户端在发起新请求之前,必须能发现服务器及所有中间设备是否支持 HTTP2.0 协议。有三种可能的情况:

      • 通过 TLS 和 ALPN 发起新的 HTTPS 连接;
      • 根据之前的信息发起新的 HTTP 连接;
      • 没有之前的信息而发起新的 HTTP 连接。
    • HTTPS 协商过程中有一个环节会使用 ALPN(应用层协议协商)。减少网络延迟是 HTTP 2.0 的关键条件,因此在建立 HTTPS 连接时一定会用到 ALPN 协商。

    • 通过常规非加密信道建立 HTTP2.0 连接需要多做一点工作。因为 HTTP1.0 和 HTTP2.0 都使用同一个端口(80),有没有服务器是否支持 HTTP2.0 的其他任何信息,此时客户端只能使用 HTTP Upgrade 机制通过协调确定适当的协议:

    1
    2
    3
    4
    5
    Upgrade: HTTP/2.0
    HTTP2-Settings: (SETTINGS payload) ➋
    HTTP/1.1 200 OK ➌
    HTTP/1.1 101 Switching Protocols ➍
    ...
    1
    2
    3
    4
    ➊ 发起带有 HTTP 2.0 Upgrade 首部的 HTTP 1.1 请求
    ➋ HTTP/2.0 SETTINGS 净荷的 Base64 URL 编码
    ➌ 服务器拒绝升级,通过 HTTP 1.1 返回响应
    ➍ 服务器接受 HTTP 2.0 升级,切换到新分帧