3
原创不易,如需转载请【联系作者】或【署名作者并注明文章出处】

谈起http协议,大家第一印象一般都会直接想到tcp-ip + ssl/tls 握手过程。今天从另一个角度为大家梳理一下http相关的一些知识点。

本文主要有7个方面,分别是

1、http演进历史,会大致介绍一下每个版本的更新内容、遇到的问题与当时的改进方案
2、http缓存策略
3、跨域策略
4、http的并发问题
5、get/post区别与常见端口号
6、一些开放性的问题
7、最后把本文成文过程中参考的各位巨人的肩膀给罗列出来。

一、HTTP的演进

1、http 0.9

  • 只允许客户端发送GET这一种请求,且不支持请求头
  • 只支持一种内容,即纯文本,支持html但 无法插入图片

2、http 1.0

  • 请求与响应支持头域
  • 响应对象以一个响应状态行开始
  • 响应对象不只限于超文本
  • 开始支持客户端通过POST方法向Web服务器提交数据,支持GET、HEAD、POST方法
  • 支持长连接(但默认还是使用短连接),缓存机制,以及身份认证

3、http 1.1

新特性:
  • 默认为长连接
HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection:keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。
  • 提供了范围请求功能(宽带优化)
HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。这是支持文件断点续传的基础。
  • 提供了虚拟主机的功能(HOST域)
在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
  • 多了一些缓存处理字段
HTTP/1.1在1.0的基础上加入了一些cache的新特性,引入了实体标签,一般被称为e-tags,新增更为强大的Cache-Control头。
  • 错误通知的管理
在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
问题:
  • 高延迟 — 队头阻塞(Head-Of-Line Blocking)
  • 无状态特性 — 阻碍交互
    协议对于连接状态没有记忆能力,服务器并不知道它与上一条请求有何关联,换句话说就是掉登录态
  • 明文传输 — 不安全性
    传输内容没有加密,中途可能被篡改和劫持。
改进方案:
  • 针对队头阻塞:
1.将同一页面的资源分散到不同域名下,提升连接上限。虽然能公用一个 TCP 管道,但是在一个管道中同一时刻只能处理一个请求,在当前的请求没有结束之前,其他的请求只能处于阻塞状态。
2.减少请求数量
3.内联一些资源:css、base64 图片等
4.合并小文件减少资源数
  • 针对不安全性:
1.https
2.token验签
3.定制化/约定:数据加密方案

4、http 2

新特性:
  • 二进制分帧传输:
1) HTTP 2.0 的所有帧都采用二进制编码
2) 帧是最小的数据单位,每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据流。多路复用,就是在一个 TCP 连接中可以存在多个流
3) 帧:客户端与服务器通过交换帧来通信,帧是基于这个新协议通信的最小单位。
4) 消息:是指逻辑上的 HTTP 消息,比如请求、响应等,由一或多个帧组成。
5) 流:流是连接中的一个虚拟信道,可以承载双向的消息;每个流都有一个唯一的整数标识符(1、2 … N);
  • 多路复用 — 解决队头阻塞
多路复用允许同时通过单一的HTTP/2.0 连接发起多重的请求-响应消息。有了新的分帧机制后,HTTP/2.0不再依赖多个TCP 连接去处理更多并发的请求。每个数据流都拆分成很多互不依赖的帧,而这些帧可以交错(乱序发送),还可以分优先级。最后再在另一端根据每个帧首部的流标识符把它们重新组合起来。HTTP 2.0 连接都是持久化的,而且客户端与服务器之间也只需要一个连接(每个域名一个连接)即可。
  • 头部压缩 — 解决巨大的 HTTP 头部
HTTP/1.1 的首部带有大量信息,而且每次都要重复发送。HTTP/2.0 要求通讯双方各自缓存一份首部字段表,从而避免了重复传输。
  • 请求优先级 — 先获取重要数据
浏览器可以在发现资源时立即分派请求,指定每个流的优先级,让服务器决定最优的响应次序。这样请求就不必排队了,既节省了时间,也最大限度地利用了每个连接。
  • 服务端推送 — 填补空缺,提高请求效率
请求 index.html 可以把首次依赖的js、css直接返回,方法是在nginx上配置一下就行
  • 提高安全性
基于https
问题:
  • TCP 以及 TCP+TLS 建立连接的延时:TCP 连接需要和服务器进行三次握手,即消耗完 1.5 个 RTT(Round-Trip Time,往返时延)
  • TCP 的队头阻塞并没有彻底解决:

    • TCP 为了保证可靠传输,有一个“超时重传”机制,丢失的包必须等待重传确认。
    • HTTP2 出现丢包时,整个 TCP 都要等待重传,那么就会阻塞该 TCP 连接中的所有请求。
  • 多路复用导致服务器压力上升
  • 多路复用容易 Timeout

5、http 3【Google基于 UDP 协议的 QUIC 协议】

新特性:
  • 改进的拥塞控制、可靠传输
  • 快速握手
  • 集成了 TLS 1.3 加密
  • 多路复用
  • 连接迁移
问题:

NAT

在一些 NAT 网络环境下(如某些校园网),UDP 协议会被路由器等中间网络设备禁止,这时客户端会直接降级,选择 HTTPS 等备选通道,保证正常业务请求。

二、 缓存

1、缓存类型

  • 200 form memory cache :不访问服务器,一般已经加载过该资源且缓存在了内存当中,直接从内存中读取缓存。浏览器关闭后,数据将不存在(资源被释放掉了),再次打开相同的页面时,不会出现from memory cache。
  • 200 from disk cache:不访问服务器,已经在之前的某个时间加载过该资源,直接从硬盘中读取缓存,关闭浏览器后,数据依然存在,此资源不会随着该页面的关闭而释放掉下次打开仍然会是from disk cache。
  • 优先访问memory cache,其次是disk cache,最后是请求网络资源

2、强/协商缓存

1)强缓存 expires / cache-control: max-age=600

  • Expires:过期时间,如果设置了时间,则浏览器会在设置的时间内直接读取缓存,不再请求
  • Cache-Control:当值设为max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。

    • private无表明响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)public可省略表明响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存no-cache可省略缓存前必需确认其有效性no-store无不缓存请求或响应的任何内容max-age=[s]必需响应的最大值
    • (1) max-age:用来设置资源(representations)可以被缓存多长时间,单位为秒;
    • (2) s-maxage:和max-age是一样的,不过它只针对代理服务器缓存而言;
    • (3)public:可省略 指示响应可被任何缓存区缓存;响应可以被任何对象(包括:发送请求的客户端,代理服务器,等等)缓存
    • (4)private:无参数,只能针对个人用户,而不能被代理服务器缓存;
    • (5)no-cache:可省略 强制客户端直接向服务器发送请求,也就是说每次请求都必须向服务器发送。服务器接收到 请求,然后判断资源是否变更,是则返回新内容,否则返回304,未变更。这个很容易让人产生误解,使人误以为是响应不被缓存。实际上Cache-Control: no-cache是会被缓存的,只不过每次在向客户端(浏览器)提供响应数据时,缓存都要向服务器评估缓存响应的有效性。
    • (6)no-store:无参数,禁止一切缓存(这个才是响应不被缓存的意思)。

2)协商缓存

  • last-modify + if-modify-since http1.0

    • Last-Modified:浏览器向服务器发送资源最后的修改时间
    • If-Modified-Since:
    • 当资源过期时(浏览器判断Cache-Control标识的max-age过期),发现响应头具有Last-Modified声明,则再次向服务器请求时带上头if-modified-since,表示请求时间。服务器收到请求后发现有if-modified-since则与被请求资源的最后修改时间进行对比(Last-Modified),若最后修改时间较新(大),说明资源又被改过,则返回最新资源,HTTP 200 OK;若最后修改时间较旧(小),说明资源无新修改,响应HTTP 304 走缓存。
  • ETag + if-not-match HTTP 1.1

    • Etag是属于HTTP 1.1属性,它是由服务器(Apache或者其他工具)生成返回给前端,用来帮助服务器控制Web端的缓存验证。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。
    • if-not-match 当资源过期时,浏览器发现响应头里有Etag,则再次像服务器请求时带上请求头if-none-match(值是Etag的值)。服务器收到请求进行比对,决定返回200或304

3)不缓存 Pragma: no-cache / catch-control: no-store
4)缓存优先级

  • 顺序的话是先判断http1.0 的【Pragma: no-cache】再, Cache-Control 再Expires,再【 ETag,最后 Last-Modified,都满足就 304,有一项不满足就 200。】
  • 强缓存

    • expires更多是为了支持http/1.0的上古浏览器的响应头,是一个具体的时间点,可能客户端与服务器时间不一致,或者网络延迟导致时间不准确
    • cache-control: max-age是一个秒数,两者同时出现以max-age为准
  • 协商缓存

    • 一般分布式环境下(比如 CDN)很少使用ETag,因为ETag依赖 Web Server 的哈希算法,不同 Web Server、不同版本、不同的配置,都会导致同样的文件 ETag可能是不相等的。当然了,如果你能限制上述信息都一样,也可以使用ETag,并不绝对。
    • Last-Modified时间精度是秒的问题,如果1s内修改了, Last-Modified不会更改,eTag是使用了摘要算法,可以及时刷新

3、不同行为引起的缓存

  • 在URI输入栏中输入然后回车/通过书签访问

    • 浏览器发现该资源已经缓存了而且没有过期(通过Expires头部或者Cache-Control头部),没有跟服务器确认,而是直接使用了浏览器缓存的内容。其中响应内容和之前的响应内容一模一样,例如其中的Date时间是上一次响应的时间。所以我们也能看到该资源的Size为from cache
  • F5/点击工具栏中的刷新按钮/右键菜单重新加载

    • F5会让浏览器无论如何都发一个HTTP Request给Server,即使先前的响应中有Expires头部
  • Ctl+F5

    • Ctrl+F5要的是彻底的从Server拿一份新的资源过来,所以不光要发送HTTP request给Server,而且这个请求里面连If-Modified-Since/If-None-Match都没有,这样就逼着Server不能返回304,而是把整个资源原原本本地返回一份,这样,Ctrl+F5引发的传输时间变长了,自然网页Refresh的也慢一些。我们可以看到该操作返回了200,并刷新了相关的缓存控制时间。
    • 为了保证拿到的是从Server上最新的,Ctrl+F5不只是去掉了If-Modified-Since/If-None-Match,还需要添加一些HTTP Headers。按照HTTP/1.1协议,Cache不光只是存在Browser终端,从Browser到Server之间的中间节点(比如Proxy)也可能扮演Cache的作用,为了防止获得的只是这些中间节点的Cache,需要告诉他们,别用自己的Cache敷衍我,往Upstream的节点要一个最新的copy吧。
    • 在Chrome 51 中会包含两个头部信息, 作用就是让中间的Cache对这个请求失效,这样返回的绝对是新鲜的资源。Cache-Control: no-cache Pragma: no-cache

三、 跨域问题

1、原理

协议 | 站点域名 | 端口号 有一个不一样就是跨域

2、表现

服务端跨域请求的资源无法共享
只要不同源就不能共享localStorage的数据

3、解决方案

1) jsonP,JSONP只支持GET请求,优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
2) Cros,CORS支持所有类型的HTTP请求
3) iFrame嵌套
4) postMessage:postMessage(data,origin)方法允许来自不同源的脚本采用异步方式进行通信,可以实现跨文本档、多窗口、跨域消息传递

*   safari,父页面无法向iframe里的跨域页面传递信息,用url传值的方法来实现跨域存储功能,可以用页面url参数(safari浏览器可以支持超过64k个字符的长度)

5) 新的跨域策略:跨域隔离 COOP、COEP

四、 并发问题

1、 现代浏览器在与服务器建立了一个 TCP 连接后是否会在一个 HTTP 请求完成后断开?什么情况下会断开?

  • HTTP/1.0 中,一个服务器在发送完一个 HTTP 响应后,会断开 TCP 链接

    • 虽然标准中没有设定,某些服务器对 Connection: keep-alive 的 Header 进行了支持。
  • HTTP/1.1 就把 Connection 头写进标准,并且默认开启持久连接,除非请求中写明 Connection: close,那么浏览器和服务器之间是会维持一段时间的 TCP 连接

2、 一个 TCP 连接是可以发送多个 HTTP 请求的。
3、 一个 TCP 连接中 HTTP 请求发送可以一起发送么(比如一起发三个请求,再三个响应一起接收)?

  • HTTP/1.1 存在一个问题,单个 TCP 连接在同一时刻只能处理一个请求,任意两个 HTTP 请求从开始到结束的时间在同一个 TCP 连接里不能重叠。
  • HTTP/1.1 规范中规定了 Pipelining

    • 一个支持持久连接的客户端可以在一个连接中发送多个请求(不需要等待任意请求的响应)。收到请求的服务器必须按照请求收到的顺序发送响应。
    • 但是这个功能在浏览器中默认是关闭的。由于 HTTP/1.1 是个文本协议,同时返回的内容也并不能区分对应于哪个发送的请求,所以顺序必须维持一致
    • 现代浏览器默认是不开启 HTTP Pipelining
    • 问题

      • 一些代理服务器不能正确的处理 HTTP Pipelining。
      • 正确的流水线实现是复杂的。
      • Head-of-line Blocking 连接头阻塞
    • 优化

      • 维持和服务器已经建立的 TCP 连接,在同一连接上顺序处理多个请求。
      • 和服务器建立多个 TCP 连接。
  • HTTP2 提供了 Multiplexing 多路传输特性

    • 可以在一个 TCP 连接中同时完成多个 HTTP 请求

4、 为什么有的时候刷新页面不需要重新建立 SSL 连接?

  • TCP 连接有的时候会被浏览器和服务端维持一段时间。TCP 不需要重新建立,SSL 自然也会用之前的。

5、 浏览器对同一 Host 建立 TCP 连接到数量有没有限制?

  • Chrome 最多允许对同一个 Host 建立六个 TCP 连接
  • 如果图片都是 HTTPS 连接并且在同一个域名下,那么浏览器在 SSL 握手之后会和服务器商量能不能用 HTTP2

    • 能的话就使用 Multiplexing 功能在这个连接上进行多路传输
    • 用不了 HTTP2 或 https

      • 浏览器就会在一个 HOST 上建立多个 TCP 连接,连接数量的最大限制取决于浏览器设置
      • 这些连接会在空闲的时候被浏览器用来发送新的请求
      • 如果所有的连接都正在发送请求呢?那其他的请求就只能等等了。

五、请求相关

1、 get post 区别

*   Get 方法的含义是请求从服务器获取资源,这个资源可以是静态的文本、页面、图片视频等。
*   Post向 URI 指定的资源提交数据,数据就放在报文的 body 里。
*   GET 方法就是安全且幂等的, POST 都不是
*   安全和幂等的概念:
    *   在 HTTP 协议里,所谓的「安全」是指请求方法不会「破坏」服务器上的资源。
    *   所谓的「幂等」,意思是多次执行相同的操作,结果都是「相同」的。

2、 常用端口号

  • 200

    • 「204 No Content」也是常见的成功状态码,与 200 OK 基本相同,但响应头没有 body 数据。
    • 「206 Partial Content」是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分,也是服务器处理成功的状态。
  • 300

    • 301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。
    • 302 Found」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。
    • 301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。
    • 304 Not Modified」不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,用于缓存控制。
  • 400

    • 「403 Forbidden」表示服务器禁止访问资源,并不是客户端的请求出错。
  • 500

    • 500 Internal Server Error」与 400 类型,是个笼统通用的错误码,服务器发生了什么错误,我们并不知道。
    • 「501 Not Implemented」表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思。
    • 「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
    • 「503 Service Unavailable」表示服务器当前很忙,暂时无法响应服务器,类似“网络服务正忙,请稍后重试”的意思。

六、边界问题

*   A、B 机器正常连接后,B 机器突然重启,问 A 此时处于 TCP 什么状态
    *   [https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/21](https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/21)
*   一个TCP连接可以发多少个HTTP请求
    *   [https://maimai.cn/article/detail?fid=1565594485&efid=2XGge6_3eNs_d2tiQsBWRw&use_rn=1](https://maimai.cn/article/detail?fid=1565594485&efid=2XGge6_3eNs_d2tiQsBWRw&use_rn=1)
    

七、参考链接

*   [【手动加精】硬核!30 张图解 HTTP 常见的面试题](https://www.cnblogs.com/xiaolincoding/p/12442435.html)
*   [HTTP 的发展和演变](https://www.cnblogs.com/xiaolincoding/p/12442435.html)
*   [一个TCP连接可以发多少个HTTP请求](https://maimai.cn/article/detail?fid=1565594485&efid=2XGge6_3eNs_d2tiQsBWRw&use_rn=1)
*   [浏览器HTTP缓存机制](https://juejin.cn/post/6844903554587574285)
*   [强制缓存和协商缓存](https://juejin.cn/post/6844903838768431118)
*   [缓存优先级](https://segmentfault.com/q/1010000022541364)
*   [http 差异](https://zhuanlan.zhihu.com/p/102561034)
*   [HTTP 0.9 HTTP 1.0 HTTP 1.1 HTTP 2.0区别](https://www.cnblogs.com/wupeixuan/p/8642100.html)
*   [HTTP缓存控制小结](https://imweb.io/topic/5795dcb6fb312541492eda8c)
原创不易,如需转载请【联系作者】或【署名作者并注明文章出处】

Logic
49 声望1 粉丝

Think Young, Do Simple.