|
| 1 | +--- |
| 2 | +layout: doc |
| 3 | +outline: deep |
| 4 | +--- |
| 5 | +应用层协议,http是无状态协议,意味着服务器不会在两个请求之间保存任何数据 |
| 6 | + |
| 7 | +发送多个http请求是串行的 |
| 8 | + |
| 9 | +## http无状态但是并非无会话 |
| 10 | +借助http cookie可以共享相同的上下文 |
| 11 | + |
| 12 | +## cookie带来的安全问题 |
| 13 | +标记为secure的cookie只会通过https加密后的请求发送给服务端,可以防止中间人攻击,但是无法阻止js api拿到cookie |
| 14 | + |
| 15 | +标记为httpnoly将阻止js api拿到cookie,缓解xss攻击 |
| 16 | +## http 发展 |
| 17 | + |
| 18 | +### http1.1的提升 |
| 19 | +1. tcp连接可以复用 |
| 20 | +2. 通过host标头,不同域名可以配置在同一个ip地址的服务器上 |
| 21 | +3. 引入额外的缓存控制机制 |
| 22 | +4. 增加管线化技术,请求发送成功之后即可发送下一个,不必等待上一个请求的响应,但是支持不佳和复杂性很少使用 |
| 23 | +### http2.0的提升 |
| 24 | +1. 二进制协议,非文本协议,无法手动读取和创建 |
| 25 | +2. 多路复用,可以通过同一个连接发送并发请求。解决流水线模式的队头阻塞问题 |
| 26 | +3. 压缩请求头(数据帧和报头帧分离,这将允许报头压缩)。由于请求头在一组请求里通常很相似,减少了数据传输的消耗 |
| 27 | + |
| 28 | +HTTP2允许在单个tcp内处理多个请求和响应,这是通过将信息包装成二进制帧,并在连接上以编号流的形式发送请求和响应来实现的 |
| 29 | + |
| 30 | +帧代表着最小的数据单位,每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据流。 |
| 31 | + |
| 32 | +多路复用,就是在一个 TCP 连接中可以存在多条流。换句话说,也就是可以发送多个请求,可以通过帧中的标识知道属于哪个请求 |
| 33 | +<img src="https://mdn.github.io/shared-assets/images/diagrams/http/messages/http-2-connection.png" alt="使用单个 TCP 连接在 HTTP/2 中多路复用请求和响应。" loading="lazy"> |
| 34 | +请求不一定连续,例如流9不需要流7结束,来自多个流的数据通常在连接上交错 |
| 35 | + |
| 36 | +也可以为每个流或者资源设置优先级,低优先级的带宽比高优先级少 |
| 37 | + |
| 38 | +由于每个帧都有一个与之关联的流 ID,因此客户端和服务器无需按顺序处理 HTTP 请求和响应。因此,HOL 阻塞问题在 HTTP 层得到解决,但现在转移到了 TCP 层。 |
| 39 | +## HTTP/1.x中的连接管理 |
| 40 | +有几种模型:短期连接、持久连接和HTTP 流水线 |
| 41 | + |
| 42 | +后面两种是1.1新引入的 |
| 43 | +<img src="https://developer.mozilla.org/en-US/docs/Web/HTTP/…on_management_in_HTTP_1.x/http1_x_connections.png" alt="比较三种 HTTP/1.x 连接模型的性能:短暂连接、持久连接和 HTTP 流水线。" width="1012" height="670" loading="lazy"> |
| 44 | + |
| 45 | +### 短暂连接(1.0默认模型) |
| 46 | +HTTP/1.0 默认为每一对 HTTP 请求/响应都打开一个单独的 TCP 连接,通过设置connection除了close之外任何值会变成持久化 |
| 47 | +### 持久连接(1.1默认模型) |
| 48 | +tcp连接可以给不同请求复用 |
| 49 | +在 HTTP/1.1 中,不再需要标头(但它通常被添加作为针对需要回退到 HTTP/1.0 的情况的防御措施)。 |
| 50 | +### http流水线 |
| 51 | +默认情况下,HTTP请求是按顺序发出的。只有在收到当前请求的响应后才会发出下一个请求。由于它们受到网络延迟和带宽限制的影响,这可能会导致服务器在看到下一个请求之前有显著的延迟。 |
| 52 | + |
| 53 | +1. 流水线要求客户端只有在前一个请求成功发送后才开始发送后续请求。但这些请求可以不等待其响应就发送。 |
| 54 | +2. 它还要求服务器按照收到请求的顺序发送响应。 |
| 55 | +3. 客户端收到的响应也需要按顺序进行处理。 |
| 56 | + |
| 57 | +这意味着客户端和服务器始终需要使用流水线按顺序处理请求和响应。 |
| 58 | + |
| 59 | +这种请求和响应的排序是必须的,否则客户端和服务器就无法确定相应的请求和响应。所以会产生队头阻塞 |
| 60 | + |
| 61 | +这也使得流水线的实现存在缺陷且容易出错,尤其是在中间有代理的情况下,因此几乎所有 浏览器都默认禁用流水线。 |
| 62 | +## 请求/响应结构 |
| 63 | +<img src="https://mdn.github.io/shared-assets/images/diagrams/http/messages/http-message-anatomy.svg"/> |
| 64 | +请求和响应都具有相似的结构: |
| 65 | + |
| 66 | +1. 起始行(请求行)是一行,描述 HTTP 版本以及请求方法或请求结果。由`<method> <request-target> <protocol>`组成 |
| 67 | +2. 一组可选的HTTP 标头,其中包含描述消息的元数据。例如,对资源的请求可能包含该资源允许的格式,而响应可能包含标头以指示返回的实际格式。 |
| 68 | +3. 空行,表明消息的元数据已完成。 |
| 69 | +4. 可选主体,包含与消息相关的数据。这可能是在请求中发送到服务器的 POST 数据,也可能是在响应中返回给客户端的某些资源。消息是否包含主体由起始行和 HTTP 标头决定。 |
| 70 | + |
| 71 | +HTTP 消息的起始行和报头统称为请求的头,之后包含其内容的部分称为正文。 |
| 72 | + |
| 73 | +## 一个tcp里请求串行发送?(与协议有关) |
| 74 | +在 HTTP/1.1 中,如果您想并行发出两个请求(单个tcp上请求是依次发送的),则必须打开两个tcp连接: |
| 75 | + |
| 76 | +<img src="https://mdn.github.io/shared-assets/images/diagrams/http/messages/http-1-connection.png" alt="并行向服务器发出两个 HTTP 请求" loading="lazy"> |
| 77 | + |
| 78 | +这意味着浏览器可以同时下载和渲染的资源数量受到限制,通常限制为 6 个并行(tcp)连接。 |
| 79 | + |
| 80 | +但是对于http2,请求是并行发送的 |
| 81 | +## 参考 |
| 82 | +[HTTP/1 和 HTTP/2 中的队头 (HOL) 阻塞](https://engineering.cred.club/head-of-line-hol-blocking-in-http-1-and-http-2-50b24e9e3372) |
0 commit comments