一文说透HTTP协议

Posted 路演前端

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文说透HTTP协议相关的知识,希望对你有一定的参考价值。

协议

由多方遵守,将初始输入由语法和语义按顺序编译(翻译)至最终目标的约定叫协议。



由此可见,协议由语法、语义和顺序三要素组成。


  • 语法,就是这一段内容要符合一定的规则和格式。例如,括号要成对,结束要使用分号等。

  • 语义,就是这一段内容要代表某种意义。例如数字减去数字是有意义的,数字减去文本一般来说就没有意义。

  • 顺序 ,就是先做什么,后做什么。例如,可以先加上某个数值,然后再减去某个数值。


HTTP


超文本传输协议(HyperText Transfer Protocol)的缩写,即HTTP。


HTTP是一种用于分布式、协作式和超媒体信息系统的应用层协议,是万维网的数据通信的基础。


版本演进


HTTP/0.9


特性:

  • 基于 TCP/IP 协议的应用层协议。不涉及数据包(packet)传输,默认使用80端口。

  • 只接受GET一种请求方法

  • 协议规定,服务器只能回应html格式的字符串,不能回应别的格式。


请求命令样例:

GET /index.html

TCP 连接建立后,客户端向服务器请求网页index.html。

<html> <body>Hello World</body></html>

服务器发送完毕后就关闭TCP连接。



HTTP/1.0


特性:

  • 支持发送任何格式的内容。

  • 引入了POST命令和HEAD命令。

  • HTTP请求和回应的格式要求除了数据部分,每次通信都必须包括头信息(HTTP Header)。

  • 每个TCP连接只能发送一个请求,发送数据完毕,连接就关闭。


请求命令样例:

GET / HTTP/1.0User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)Accept: */*
  • GET请求命令必须在尾部添加协议版本(HTTP/1.0)。

  • User-Agent描述客户端的情况。

  • Accept声明请求的返回可接收的数据格式。*/*代表接收任何数据格式。

HTTP/1.0 200 OKContent-Type: text/plainContent-Length: 137582Expires: Thu, 05 Dec 1997 16:00:00 GMTLast-Modified: Wed, 5 August 1996 15:55:28 GMTServer: Apache 0.84<html> <body>Hello World</body></html>

回应的格式是"头信息 + 一个空行(\r\n) + 数据"。


  • 第一行是"协议版本 + 状态码(status code) + 状态描述"。

  • Content-Type字段用于描述数据格式,数据类型的总称是MIME type,可在尾部使用分号,添加参数。

// 发送类型是网页,编码是UTF-8。Content-Type: text/html; charset=utf-8 


HTTP/1.1


特性:

  • 引入了持久连接(persistent connection),即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive

  • 客户端可在最后一个请求时,发送Connection: close,要求服务器关闭TCP连接。

  • 对于同一个域名,大部分浏览器允许同时建立6个持久连接。

  • 引入管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求,但服务器还是按照顺序处理请求。

  • 增加了对PUT、PATCH、HEAD、 OPTIONS、DELETE的支持

  • 客户端请求的头信息新增了Host字段,用来指定服务器的域名,可以将请求发往同一台服务器上的不同网站(虚拟主机)。

  • Content-length字段的作用是声明本次回应的数据长度。
    使用的前提是服务器发送回应之前,必须知道回应的数据长度,才能从多个返回中知晓哪个返回属于自身的请求回应。

  • 支持分块传输编码
    请求或回应的头信息有Transfer-Encoding字段,就表明回应将由数量未定的数据块组成。

Transfer-Encoding: chunked

  • 每个非空的数据块之前,会有一个16进制的数值,表示这个块的长度。最后是一个大小为0的块,就表示本次回应的数据发送完了,示例如下:

HTTP/1.1 200 OKContent-Type: text/plainTransfer-Encoding: chunked25This is the data in the first chunk1Cand this is the second one3con8sequence0


HTTP/2


特性:

  • 仅在HTTPS环境生效。

  • 一个彻底的二进制协议。
    头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。收益在于可以定义额外的帧,如果使用文本实现,解析数据将会变得非常麻烦,二进制解析则方便得多。

  • 多工

举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。

这样双向的、实时的通信,就叫做多工(Multiplexing)。

  • HTTP/2 复用TCP连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了"队头堵塞"。

  • 数据流(stream)
    由于多工的特性,HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。
    HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。
    数据流可以由客户端指定优先级,优先级越高,服务器就会越早回应。
    数据流可以由客户端取消,同时不关闭TCP连接。

  • 头信息压缩(header compression)

HTTP 协议不带有状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如Cookie和User Agent,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。

  • 首次,客户端使用gzip或compress压缩头信息后发送请求;
    客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号;
    之后每次请求只发送索引号即可。

  • 服务器推送(server push)
    HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。

假设客户端请求一个页面,该页面中包含较多图片等静态资源。

常规情况下,渲染该页面需要发送两次以上的请求才可完成。

采用server push,服务器可将页面相关静态资源主动一起发送给客户端。


理解

由客户端和服务端遵守,符合“协议”的三要素,即:

  • 符合语法,浏览器只认可该格式。分别由状态、首部和内容组成。

  • 符合语义,比如状态 200,表示网页成功返回。

  • 符合顺序,浏览器通过 HTTP 请求才能拿到一串 HTTP 返回值。



知识要点

http的无状态

无状态的意义:客户端和服务器在某次会话中产生的数据不会被保留

  • http 协议对于事务处理没有记忆能力

  • 对同一个url请求没有上下文关系

  • 每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况

  • 服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器

  • 请求过的资源下一次会继续进行请求


http-cache

  • 减少了冗余的数据传输,减少网络花销

  • 减少服务器端的压力

  • Web 缓存能够减少延迟与网络阻塞,进而减少客户端渲染耗时

本地缓存

指浏览器请求资源时命中了浏览器本地的缓存资源,浏览器并不会发送真正的请求给服务器了。

逻辑流程

  1. 第一次浏览器发送请求给服务器时,此时浏览器还没有本地缓存副本,服务器返回资源给浏览器,响应码是200 OK,浏览器收到资源后,把资源和对应的响应头一起缓存下来。

  2. 第二次浏览器准备发送请求给服务器时候,浏览器会先检查上一次服务端返回的响应头信息中的Cache-Control,它的值是一个相对值,单位为秒,表示资源在客户端缓存的最大有效期,过期时间为第一次请求的时间减去Cache-Control的值,过期时间跟当前的请求时间比较:

    • 如果本地缓存资源没过期,那么命中缓存,不再请求服务器;

    • 如果没有命中,浏览器就会把请求发送给服务器,进入缓存协商阶段。

在请求/响应头中由Cache-Control和Expires实现


Cache-Control

有多个可选值代表不同的意义:

  • no-cache:不使用本地缓存。需要使用缓存协商,先与服务器确认返回的响应是否被更改,如果之前的响应中存在ETag,那么请求的时候会与服务端验证,如果资源未被更改,则可以避免重新下载。

  • no-store:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送一个请求,每次都会下载完整的资源。

  • public:可以被所有的用户缓存,包括终端用户和CDN等中间代理服务器。

  • private:只能被终端用户的浏览器缓存,不允许CDN等中继缓存服务器对其缓存。

  • max-age:从当前请求开始,允许获取的响应被重用的最长时间(秒)。


Expires

一个绝对时间,时间格式是如Mon, 10 Jun 2015 21:31:12 GMT,只要发送请求时间是在Expires之前,那么本地缓存始终有效,否则就会去服务器发送请求获取新的资源。

如果同时出现Cache-Control:max-age和Expires,那么max-age优先级更高。


缓存协商

逻辑流程

当第一次请求时服务器返回的响应头中存在以下情况时

  • 没有 Cache-Control 和 Expires

  • Cache-Control 和 Expires 过期了

  • Cache-Control 的属性设置为 no-cache


浏览器第二次请求时就会与服务器进行协商,询问浏览器中的缓存资源是不是旧版本,需不需要更新,此时,服务器就会做出判断:

  • 如果缓存和服务端资源的最新版本是一致的,那么就无需再次下载该资源,服务端直接返回304 Not Modified 状态码;

  • 如果服务器发现浏览器中的缓存已经是旧版本了,那么服务器就会把最新资源的完整内容返回给浏览器,状态码就是200 Ok。

根据HTTP的另外两组头信息进行判断,分别是:Last-Modified/If-Modified-Since 与 ETag/If-None-Match。


Last-Modified 与 If-Modified-Since

  1. 浏览器第一次请求资源时,服务器会把资源的最新修改时间Last-Modified:Thu, 29 Dec 2011 18:23:55 GMT放在响应头中返回给浏览器

 
Cache-Control:max-age=3600Expires: Fri, Jan 12 2018 00:27:04 GMTLast-Modified: Thu, 29 Dec 2011 18:23:55 GMT

  1. 第二次请求时,浏览器就会把上一次服务器返回的修改时间放在请求头If-Modified-Since:Thu, 29 Dec 2011 18:23:55发送给服务器。

If-Modified-Since: Thu, 29 Dec 2011 18:23:55 GMT

服务器就会拿这个时间跟服务器上的资源的最新修改时间进行对比:

  • 如果两者相等或者大于服务器上的最新修改时间,那么表示浏览器的缓存是有效的,此时缓存会命中,服务器就不再返回内容给浏览器了,同时Last-Modified头也不会返回,因为资源没被修改,返回了也没什么意义。

  • 如果没命中缓存则最新修改的资源连同Last-Modified头一起返回。


ETag与If-None-Match

与Last-Modified/If-Modified-Since类似,唯一的区别是它基于资源的内容的摘要信息(比如MD5 hash)来判断,好处是如果因为某种原因到时资源的修改时间没改变,那么用ETag就能区分资源是不是有被更新。

Cache-Control: public, max-age=31536000ETag: "15f0fff99ed5aae4edffdd6496d7131f"

浏览器发送第二次请求时,会把第一次的响应头信息ETag的值放在If-None-Match的请求头中发送到服务器,与最新的资源的摘要信息对比。

If-None-Match: "15f0fff99ed5aae4edffdd6496d7131f"

如果相等,取浏览器缓存,否则内容有更新,最新的资源连同最新的摘要信息返回。



以上是关于一文说透HTTP协议的主要内容,如果未能解决你的问题,请参考以下文章

一文说透kafka底层架构

一文说透架构设计的本质

如何排查CentOS 7执行yum命令失败问题?一文说透!

一文说透以太坊上TVL最大的二层网络:Arbitrum

用户密码加密存储十问十答,一文说透密码安全存储

2021年抢先复盘:一文说透BetaAlpha等4种区块链收益