这本 HTTP 方面的小册子还蛮不错,已经二刷了 😜
这次做了一些笔记,方便自己和其他人翻阅和复习,因为这本书是 2014 年出的初版,所以有一些不怎么常用的技术,笔记中就省略了,只记一些比较常用的 ~
如果希望获取本书的 PDF 资源,可以关注文末二维码加微信群找群主要~
1. 了解 Web 及网络基础
1.1 网络基础 TCP/IP
通常使用的网络(包括互联网)是在 TCP/IP 协议族的基础上运作,而 HTTP 属于它内部的一个子集。
按层次分为以下 4 层:应用层、传输层、网络层和数据链路层。
- 应用层: 决定了向用户提供应用服务时通信的活动,比如 FTP、DNS、HTTP
- 传输层: 对上层应用层,提供处于网络连接中的两台计算机之间的数据传输,比如 TCP、UDP
- 网络层: 用来处理在网络上流动的数据包,该层规定了通过怎样的路径(所谓的传输路线)到达对方计算机,并把数据包传送给对方;与对方计算机之间通过多台计算机或网络设备进行传输时,网络层所起的作用就是在众多的选项内选择一条传输路线。
- 数据链路层: 用来处理连接网络的硬件部分
利用 TCP/IP 协议族进行网络通信时,会通过分层顺序与对方进行通信。发送端从应用层往下走,接收端则往应用层往上走。
以 HTTP 为例,一次通信的过程
- 首先作为发送端的客户端在应用层(HTTP 协议)发出获取 Web 页面的 HTTP 请求
- 接着,为了传输方便,在传输层(TCP 协议)把从应用层处收到的数据(HTTP 请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层。
- 在网络层(IP 协议),增加作为通信目的地的 MAC 地址后转发给链路层。这样一来,发往网络的通信请求就准备齐全了
- 接收端的服务器在链路层接收到数据,按序往上层发送,一直到应用层。当传输到应用层,才能算真正接收到由客户端发送过来的 HTTP 请求。
发送端在层与层之间传输数据时,每经过一层时必定会被打上一个该层所属的首部信息。反之,接收端在层与层传输数据时,每经过一层时会把对应的首部消去。
这种把数据信息包装起来的做法称为封装(encapsulate)。
1.2 三次握手
为了准确无误地将数据送达目标处,TCP 协议采用了三次握手(three-way handshaking)策略。握手过程中使用了 TCP 的标志(flag) —— SYN(synchronize) 和 ACK(acknowledgement)。
发送端首先发送一个带 SYN 标志的数据包给对方。接收端收到后,回传一个带有 SYN/ACK 标志的数据包以示传达确认信息。最后,发送端再回传一个带 ACK 标志的数据包,代表“握手”结束。
发送端首先发送一个带 SYN 标志的数据包给对方。接收端收到后,回传一个带有 SYN/ACK 标志的数据包以示传达确认信息。最后,发送端再回传一个带 ACK 标志的数据包,代表“握手”结束。
1.3 负责域名解析的 DNS 服务
DNS(Domain Name System)服务是和 HTTP 协议一样位于应用层的协议。它提供域名到 IP 地址之间的解析服务。
1.4 各协议与 HTTP 协议的关系
通过这张图来了解下 IP 协议、TCP 协议和 DNS 服务在使用 HTTP 协议的通信过程中各自发挥了哪些作用。
1.5 URI 和 URL
了解一下 URI 的各部分
- 协议方案名: 使用
http:
或https:
等协议方案名获取访问资源时要指定协议类型。不区分字母大小写,最后附一个冒号。也可使用data:
或javascript:
这类指定数据或脚本程序的方案名。 - 登录信息(认证): 指定用户名和密码作为从服务器端获取资源时必要的登录信息(身份认证)。此项是可选项。
- 服务器地址: 使用绝对 URI 必须指定待访问的服务器地址。地址可以是类似
hackr.jp
这种 DNS 可解析的名称,或是192.168.1.1
这类 IPv4 地址名,还可以是[0:0:0:0:0:0:0:1]
这样用方括号括起来的 IPv6 地址名。 - 服务器端口号: 指定服务器连接的网络端口号。此项也是可选项,若用户省略则自动使用默认端口号。
- 带层次的文件路径: 指定服务器上的文件路径来定位特指的资源。这与 UNIX 系统的文件目录结构相似。
- 查询字符串: 针对已指定的文件路径内的资源,可以使用查询字符串传入任意参数。此项可选。
- 片段标识符: 使用片段标识符通常可标记出已获取资源中的子资源(文档内的某个位置)。但在 RFC 中并没有明确规定其使用方法。该项也为可选项
2. 简单的 HTTP 协议
2.1 HTTP 是不保存状态的协议
HTTP 是一种不保存状态,即无状态(stateless)协议。HTTP 协议自身不对请求和响应之间的通信状态进行保存。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把 HTTP 协议设计成如此简单的。
HTTP1.1 虽然是无状态协议,但为了实现期望的保持状态功能,于是引入了 Cookie 技术。
2.2 告知服务器意图的 HTTP 方法
- GET 获取资源: 用来请求访问已被 URI 识别的资源,指定的资源经服务器端解析后返回响应内容。 如果请求的资源是文本,那就保持原样返回;如果是像 CGI(Common Gateway Interface,通用网关接口)那样的程序,则返回经过执行后的输出结果。
- POST 传输实体主体: 用来传输实体的主体 虽然用 GET 方法也可以传输实体的主体,但一般不用 GET 方法进行传输,而是用 POST 方法。虽说 POST 的功能与 GET 很相似,但 POST 的主要目的并不是获取响应的主体内容。
- PUT 传输文件: 在请求报文的主体中包含文件内容,然后保存到请求 URI 指定的位置 鉴于 HTTP1.1 的 PUT 方法自身不带验证机制,任何人都可以上传文件,存在安全性问题,因此一般的 Web 网站不使用该方法。
- HEAD 获得报文首部: 和 GET 方法一样,只是不返回报文主体部分。 用于确认 URI 的有效性及资源更新的日期时间等。
- DELETE 删除文件: 用来删除文件,是与 PUT 相反的方法。DELETE 方法按请求 URI 删除指定的资源。 HTTP1.1 的 DELETE 方法本身和 PUT 方法一样不带验证机制,所以一般的 Web 网站也不使用 DELETE 方法。
- OPTIONS 询问支持的方法: 用来查询针对请求 URI 指定的资源支持的方法。
- TRACE 追踪路径: 让 Web 服务器端将之前的请求通信环回给客户端的方法。 发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器端就将该数字减 1,当数值刚好减到 0 时,就停止继续传输,最后接收到请求的服务器端则返回状态码 200 OK 的响应。 但 TRACE 方法本来就不怎么常用,再加上它容易引发 XST(Cross-Site Tracing,跨站追踪)攻击,通常就更不会用到了。
- CONNECT 要求用隧道协议连接代理: 要求在与代理服务器通信时建立隧道,实现用隧道协议进行 TCP 通信。 主要使用 SSL(Secure Sockets Layer,安全套接层)和 TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输。
方法 | 说明 | 支持的 HTTP 协议版本 |
GET | 获取资源 | 1.0、1.1 |
POST | 传输实体主体 | 1.0、1.1 |
PUT | 传输文件 | 1.0、1.1 |
HEAD | 获得报文首部 | 1.0、1.1 |
DELETE | 删除文件 | 1.0、1.1 |
OPTIONS | 询问支持的方法 | 1.1 |
TRACE | 追踪路径 | 1.1 |
CONNECT | 要求用隧道协议连接代理 | 1.1 |
LINK | 建立和资源之间的联系 | 1.0 |
UNLINE | 断开连接关系 | 1.0 |
LINK 和 UNLINK 已被 HTTP1.1 废弃,不再支持。
2.3 持久连接节省通信量
HTTP 协议的初始版本中,每进行一次 HTTP 通信就要断开一次 TCP 连接。
比如,使用浏览器浏览一个包含多张图片的 HTML 页面时,在发送请求访问 HTML 页面资源的同时,也会请求该 HTML 页面里包含的其他资源。因此,每次的请求都会造成无谓的 TCP 连接建立和断开,增加通信量的开销。
持久链接 keep-alive
HTTP1.1 和一部分的 HTTP1.0 想出了持久连接(keep-alive)的方法。持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。
持久连接的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。另外,减少开销的那部分时间,使 HTTP 请求和响应能够更早地结束,这样 Web 页面的显示速度也就相应提高了。
在 HTTP1.1 中,所有的连接默认都是持久连接,但在 HTTP1.0 内并未标准化。
管线化 pipelining
持久连接使得多数请求以管线化(pipelining)方式发送成为可能。从前发送请求后需等待并收到响应,才能发送下一个请求。管线化技术出现后,不用等待响应亦可直接发送下一个请求。
这样就能够做到同时并行发送多个请求,而不需要一个接一个地等待响应了。
用持久连接可以让请求更快结束。而管线化技术则比持久连接还要快。请求数越多,时间差就越明显。
2.4 使用 Cookie 的状态管理
HTTP 是无状态协议,它不对之前发生过的请求和响应的状态进行管理。也就是说,无法根据之前的状态进行本次的请求处理。
假设要求登录认证的 Web 页面本身无法进行状态的管理(不记录已登录的状态),那么每次跳转新页面不是要再次登录,就是要在每次请求报文中附加参数来管理登录状态。
Cookie 技术通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。Cookie 会根据从服务器端发送的响应报文内的一个叫做 Set-Cookie
的首部字段信息,通知客户端保存 Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入 Cookie 值后发送出去。
3. HTTP 报文内的 HTTP 信息
3.1 编码提升传输速率
HTTP 可以在传输过程中通过编码提升传输速率。
3.2 压缩传输的内容编码
内容编码指明应用在实体内容上的编码格式,并保持实体信息原样压缩。
常用的内容编码有:gzip(GNU zip)、compress(UNIX 系统的标准压缩)deflate(zlib)、identity(不进行编码)
3.3 分割发送的分块传输编码
在 HTTP 通信过程中,请求的编码实体资源尚未全部传输完成之前,浏览器无法显示请求页面。在传输大容量数据时,通过把数据分割成多块,能够让浏览器逐步显示页面。
这种把实体主体分块的功能称为分块传输编码(Chunked Transfer Coding)。
分块传输编码会将实体主体分成多个部分(块)。每一块都会用十六进制来标记块的大小,而实体主体的最后一块会使用“0(CR+LF)”来标记。
使用分块传输编码的实体主体会由接收的客户端负责解码,恢复到编码前的实体主体。
3.4 发送多种数据的多部分对象集合
在 HTTP 报文中使用多部分对象集合时,需要在首部字段里加上 Content-type
:
- multipart/form-data: 在 Web 表单文件上传时使用。
- multipart/byteranges: 状态码 206(Partial Content,部分内容)响应报文包含了多个范围的内容时使用。
3.5 获取部分内容的范围请求
如果下载过程中遇到网络中断的情况,那就必须重头开始。为了解决上述问题,需要一种可恢复的机制。所谓恢复是指能从之前下载中断处恢复下载。
要实现该功能需要指定下载的实体范围,指定范围发送的请求叫做范围请求(Range Request)。针对范围请求,响应会返回状态码 206。
比如:
- 5001~10 000 字节:
Range: bytes=5001-10000
- 从 5001 字节之后全部的:
Range: bytes=5001-
- 从一开始到 3000 字节和 5000~7000 字节的多重范围:
Range: bytes=-3000, 5000-7000
3.6 内容协商返回最合适的内容
内容协商机制是指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。内容协商会以响应资源的语言、字符集、编码方式等作为判断的基准。
包含在请求报文中的某些首部字段(如下)就是判断的基准:Accept
、Accept-Charset
、Accept-Encoding
、Accept-Language
、Content-Language
有以下几种类型:
- 服务器驱动协商: 以请求的首部字段为参考,在服务器端自动处理。但对用户来说,以浏览器发送的信息作为判定的依据,并不一定能筛选出最优内容。
- 客户端驱动协商: 用户从浏览器显示的可选项列表中手动选择。还可以利用 JavaScript 脚本在 Web 页面上自动进行上述选择。比如按 OS 的类型或浏览器类型,自行切换成 PC 版页面或手机版页面。
- 透明协商: 是服务器驱动和客户端驱动的结合体,是由服务器端和客户端各自进行内容协商的一种方法。
4. 返回结果的 HTTP 状态码
状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户可以知道服务器端是正常处理了请求,还是出现了错误。
4.1 状态码告知从服务器端返回的请求结果
数字中的第一位指定了响应类别,后两位无分类
类别 | 原因短语 | |
1XX | Informational(信息性状态码) | 接收的请求正在处理 |
2XX | Success(成功状态码) | 请求正常处理完毕 |
3XX | Redirection(重定向状态码) | 需要进行附加操作以完成请求 |
4XX | Client Error(客户端错误状态码) | 服务器无法处理请求 |
5XX | Server Error(服务器错误状态码) | 服务器处理请求出错 |
4.2 2xx 成功
请求被正常处理了。
- 200 OK: 表示从客户端发来的请求在服务器端被正常处理了
- 204 No Content: 表示服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分。另外,也不允许返回任何实体的主体。比如,当从浏览器发出请求处理后,返回 204 响应,那么浏览器显示的页面不发生更新。一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用。
- 206 Partial Content: 表示客户端进行了范围请求,而服务器成功执行了这部分的 GET 请求。响应报文中包含由 Content-Range 指定范围的实体内容。
4.3 3XX 重定向
浏览器需要执行某些特殊的处理以正确处理请求。
- 301 Moved Permanently: 永久性重定向。该状态码表示请求的资源已被分配了新的 URI,以后应使用资源现在所指的 URI。也就是说,如果已经把资源对应的 URI 保存为书签了,这时应该按 Location 首部字段提示的 URI 重新保存。
- 302 Found: 临时性重定向。该状态码表示请求的资源已被分配了新的 URI,希望用户(本次)能使用新的 URI 访问。已移动的资源对应的 URI 将来还有可能发生改变。
- 303 See Other: 表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。303 和 302 有着相同的功能,但 303 状态码明确表示客户端应当采用 GET 方法获取资源,这点与 302 状态码有区别。
- 304 Not Modified: 客户端发送 GET 方法的请求头中包含
If-Match
、If-Modified-Since
、If-None-Match
、If-Range
、If-Unmodified-Since
中任一首部时,服务器端允许请求访问资源,但未满足条件的情况。304 状态码返回时,不包含任何响应的主体部分。304 虽然被划分在 3XX 类别中,但是和重定向没有关系。 - 307 Temporary Redirect: 临时重定向,与 302 Found 有着相同的含义。
4.4 4XX 客户端错误
客户端发生了错误。
- 400 Bad Request: 表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 一样对待该状态码。
- 401 Unauthorized: 表示发送的请求需要有通过 HTTP 认证的认证信息。若之前已进行过一次请求,则表示用户认证失败。返回含有 401 的响应必须包含一个适用于被请求资源的
WWW-Authenticate
首部用以质询用户信息。当浏览器初次接收到 401 响应,会弹出认证用的对话窗口。 - 403 Forbidden: 对请求资源的访问被服务器拒绝了。服务器端没有必要给出拒绝的详细理由,但如果想作说明的话,可以在实体的主体部分对原因进行描述,这样就能让用户看到了。比如未获得文件系统的访问授权、访问权限出现某些问题等情景。
- 404 Not Found: 服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由时使用。
4.5 5XX 服务器错误
服务器本身发生错误。
- 500 Internal Server Error: 服务器端在执行请求时发生了错误,也有可能是 Web 应用存在的 bug 或某些临时的故障。
- 503 Service Unavailable: 表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入
RetryAfter
首部字段再返回给客户端。