开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 22 天,点击查看活动详情
原文来自我的个人博客
1. HTTP 基础
1.1 HTTP 协议是什么?
HTTP (HyperText Transfer Protocol),即超文本运输协议,是实现网络通信的一种规范
在计算机和网络世界有,存在不同的协议,如广播协议、寻址协议、路由协议等等......
而 HTTP 是一个传输协议,即将数据由 A 传到 B 或将 B 传输到 A ,并且 A 与 B 之间能够存放很多第三方,如: A<=>X<=>Y<=>Z<=>B
传输的数据并不是计算机底层中的二进制包,而是完整的、有意义的数据,如 HTML 文件, 图片文件, 查询结果等超文本,能够被上层应用识别
在实际应用中,HTTP 常被用于在 Web浏览器 和 网站服务器 之间传递信息,以明文方式发送内容,不提供任何方式的数据加密
1.2 HTTP 协议的特点
- 应用层协议(下面可以是
TCP/IP) - 信息纯文本传输
- 支持客户/服务器模式
- 简单快速:客户向服务器请求服务时,只需传送请求方法和路径。由于
HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快 - 灵活:
HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记 - 无状态:每次请求独立,请求之间互相不影响(浏览器提供了手段维护状态比如
Cookie,Session,Storage等)
1.3 HTTP 协议的历史
1991 HTTP 0.9(实验版本)1996 HTTP 1.0(有广泛用户)1999 HTTP 1.1(影响面最大的版本)2015 HTTP 2.0(大公司基本上都是2.0了)2018 HTTP 3.0(2022 年 6 月 6 日正式发布了)
1.4 Header 和 Body
HTTP是一个文本传输协议,传输内容是人类可读的文本,大体分成两部分:- 请求头(
Header)/ 返回头 - 消息体(
Body)
- 请求头(
下面演示一个 Node.js 实战 http 请求
const net = require("net");
const response = `
HTTP/1.1 200 OK
Data: Tue,30 Jun 2022 01:00:00 GMT
Content-Type: text/plain
Connection: Closed
Hello World
`;
const server = net.createServer((socket) => {
socket.end(response);
});
server.listen(80, () => {
console.log("80端口启动");
});
从浏览器中观察
1.5. HTTPS
在上述介绍 HTTP 中,了解到 HTTP 传递信息是以明文的形式发送内容,这并不安全。而 HTTPS 出现正是为了解决 HTTP 不安全的特性
为了保证这些隐私数据能加密传输,让 HTTP 运行安全的 SSL/TLS 协议上,即 HTTPS = HTTP + SSL/TLS,通过 SSL 证书来验证服务器的身份,并为浏览器和服务器之间的通信进行加密
SSL 协议位于 TCP/IP 协议与各种应用层协议之间,浏览器和服务器在使用 SSL 建立连接时需要选择一组恰当的加密算法来实现安全通信,为数据通讯提供安全支持
流程图如下:
1.6. HTTP 和 HTTPS 的区别
HTTPS是HTTP协议的安全版本,HTTP协议的数据传输是明文的,是不安全的,HTTPS使用了SSL/TLS协议进行了加密处理,相对更安全HTTP和HTTPS使用连接方式不同,默认端口也不一样,HTTP是80,HTTPS是443HTTPS由于需要设计加密以及多次握手,性能方面不如HTTPHTTPS需要SSL,SSL证书需要钱,功能越强大的证书费用越高
2. HTTP 详情
2.1. HTTP 常见请求头
2.1.1 请求头是什么?
HTTP 头字段(HTTP header fields),是指在超文本传输协议(HTTP)的请求和响应消息中的消息头部分
它们定义了一个超文本传输协议事务中的操作参数
HTTP 头部字段可以自己根据需要定义,因此可能在 Web 服务器和浏览器上发现非标准的头字段
下面是一个 HTTP 常见的请求头:
下面是一个 HTTP 常见的响应头
2.2 常见HTTP头
2.2.1 Content-Length
-
发送给接受者的
Body内容长度(字节)- 一个
byte是8bit - UTF-8编码的字符1-4个字节、
- 一个
示例:Content-Length: 348
2.2.2 User-Agent
-
帮助区分客户端特性的字符串
- 操作系统
- 浏览器
- 制造商(手机类型等)
- 内核类型
- 版本号
示例:User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
2.2.3 Content-Type
-
帮助区分资源的媒体类型(Media Type/MIME Type)
- text/html
- text/css
- application/json
- image/jpeg
示例:Content-Type: application/x-www-form-urlencoded
2.2.4 Origin:
-
描述请求来源地址
- scheme://host:port
- 不含路径
- 可以是null
示例: Origin: yewjiwei.com
2.2.5 Accept
-
建议服务端返回何种媒体类型(MIME Type)
- */*代表所有类型(默认)
- 多个类型用逗号隔开
- 衍生的还有
- Accept-Charset能够接受的字符集 示例:Accept-Charset: utf-8
- Accept-Encoding能够接受的编码方式列表 示例:Accept-Encoding: gzip, deflate
- Accept-Language能够接受的回应内容的自然语言列表 示例:Accept-Language: en-US
示例:
-
Accept: text/plain
-
Accept-Charset: utf-8
-
Accept-Encoding: gzip, deflate
2.2.6 Referer
-
告诉服务端打开当前页面的上一张页面的URL;如果是ajax请求那么就告诉服务端发送请求的URL是什么
- 非浏览器环境有时候不发送Referer
- 常常用户行为分析
2.2.7 Connection
-
决定连接是否在当前事务完成后关闭
- HTTP1.0默认是close
- HTTP1.1后默认是keep-alive
2.2.8 Authorization
- 用于超文本传输协议的认证的认证信息
- 示例: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
2.2.9 Cache-Control
- 用来指定在这次的请求/响应链中的所有缓存机制 都必须 遵守的指令
- 示例: Cache-Control: no-cache
2.2.10 Date
- 发送该消息的日期和时间
- 示例: Date: Tue, 15 Nov 1994 08:12:31 GMT
2.3. 基本方法
- GET 从服务器获取资源(一个网址url代表一个资源)
- POST 在服务器创建资源
- PUT 在服务器修改资源
- DELETE 在服务器删除资源
- OPTIONS 跟跨域相关
- TRACE 用于显示调试信息
- CONNECT 代理
- PATCH 对资源进行部分更新(极少用)
2.4. 状态码
- 1XX: 提供信息
- 100 continue 情景:客户端向服务端传很大的数据,这个时候询问服务端,如果服务端返回100,客户端就继续传 (历史,现在比较少了)
- 101 协议切换switch protocol
告诉客户端把协议切换为WebsocketHTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade - 2xx: 成功
- 200
Ok正常的返回成功 通常用在GET - 201
Created已创建 通常用在POST - 202
Accepted已接收 比如发送一个创建POST请求,服务端有些异步的操作不能马上处理先返回202,结果需要等通知或者客户端轮询获取 - 203
Non-Authoritative Infomation非权威内容 原始服务器的内容被修改过 - 204
No Content没有内容 一般PUT请求修改了但是没有返回内容 - 205
Reset Content重置内容 - 206
Partial Content服务端下发了部分内容
- 200
- 3XX: 重定向
- 300
Multiple Choices用户请求了多个选项的资源(返回选项列表) - 301
Moved Permanently永久转移 - 302
Found资源被找到(以前是临时转移)不推荐用了 302拆成了303和307 - 303
See Other可以使用GET方法在另一个URL找到资源 - 304
Not Modified没有修改 - 305
Use Proxy需要代理 - 307
Temporary Redirect临时重定向 (和303的区别是,307使用原请求的method重定向资源, 303使用GET方法重定向资源) - 308
Permanent Redirect永久重定向 (和301区别是 客户端接收到308后,之前是什么method,之后也会沿用这个method到新地址。301,通常给用户会向新地址发送GET请求)
- 300
- 4XX: 客户端错误
- 400
Bad Request请求格式错误 - 401
Unauthorized没有授权 - 402
Payment Required请先付费 - 403
Forbidden禁止访问 - 404
Not Found没有找到 - 405
Method Not Allowed方法不允许 - 406
Not Acceptable服务端可以提供的内容和客户端期待的不一样
- 400
- 5XX: 服务端错误
- 500
Internal Server Error内部服务器错误 - 501
Not Implemented没有实现 - 502
Bad Gateway网关错误 - 503
Service Unavailable服务不可用 (内存用光了,线程池溢出,服务正在启动) - 504
Gateway Timeout网关超时 - 505
HTTP Version Not Supported版本不支持
- 500
3. TCP vs UDP
3.1. TCP
TCP(Transmission Control Protocol),传输控制协议,是一种可靠、面向字节流的通信协议,把上面应用层交下来的数据看成无结构的字节流来发送。
可以想象成流水形式的,发送方TCP会将数据放入“蓄水池”(缓存区),等到可以发送的时候就发送,不能发送就等着,TCP会根据当前网络的拥塞状态来确定每个报文段的大小。
TCP 报文首部有 20 个字节,额外开销大。
特点如下:
TCP充分地实现了数据传输时各种控制功能,可以进行丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。而这些在UDP中都没有。- 此外,
TCP作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,从而可以控制通信流量的浪费。 - 根据
TCP的这些机制,在IP这种无连接的网络上也能够实现高可靠性的通信( 主要通过检验和、序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现)
3.2 UDP
UDP(User Datagram Protocol),用户数据包协议,是一个简单的面向数据报的通信协议,即对应用层交下来的报文,不合并,不拆分,只是在其上面加上首部后就交给了下面的网络层
也就是说无论应用层交给UDP多长的报文,它统统发送,一次发送一个报文
而对接收方,接到后直接去除首部,交给上面的应用层就完成任务
UDP报头包括 4 个字段,每个字段占用 2 个字节(即 16 个二进制位),标题短,开销小
特点如下:
UDP不提供复杂的控制机制,利用IP提供面向无连接的通信服务- 传输途中出现丢包,
UDP也不负责重发 - 当包的到达顺序出现乱序时,
UDP没有纠正的功能。 - 并且它是将应用程序发来的数据在收到的那一刻,立即按照原样发送到网络上的一种机制。即使是出现网络拥堵的情况,
UDP也无法进行流量控制等避免网络拥塞行为
3.3 区别
UDP 与 TCP 两者的都位于传输层,如下图所示:
两者区别如下表所示:
| 标题 | TCP | UDP |
|---|---|---|
| 可靠性 | 可靠 | 不可靠 |
| 连接性 | 面向连接 | 无连接 |
| 报文 | 面向字节流 | 面向报文 |
| 效率 | 传输效率低 | 传输效率高 |
| 双共性 | 全双工 | 一对一、一对多、多对一、多对多 |
| 流量控制 | 滑动窗口 | 无 |
| 拥塞控制 | 慢开始、拥塞避免、快重传、快恢复 | 无 |
| 传输效率 | 慢 | 快 |
-
TCP是面向连接的协议,建立连接3次握手、断开连接四次挥手,UDP是面向无连接,数据传输前后不连接连接,发送端只负责将数据发送到网络,接收端从消息队列读取 -
TCP提供可靠的服务,传输过程采用流量控制、编号与确认、计时器等手段确保数据无差错,不丢失。UDP则尽可能传递数据,但不保证传递交付给对方 -
TCP面向字节流,将应用层报文看成一串无结构的字节流,分解为多个TCP报文段传输后,在目的站重新装配。UDP协议面向报文,不拆分应用层报文,只保留报文边界,一次发送一个报文,接收方去除报文首部后,原封不动将报文交给上层应用 -
TCP只能点对点全双工通信。UDP支持一对一、一对多、多对一和多对多的交互通信
两者应用场景如下图:
可以看到,TCP 应用场景适用于对效率要求低,对准确性要求高或者要求有链接的场景,而UDP 适用场景为对效率要求高,对准确性要求低的场景
4. HTTP 1.0 / 1.1 / 2.0 / 3.0
4.1. HTTP1.0
HTTP协议的第二个版本,第一个在通讯中指定版本号的HTTP协议版本
HTTP 1.0 浏览器与服务器只保持短暂的连接,每次请求都需要与服务器建立一个TCP连接
服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求
简单来讲,每次与服务器交互,都需要新开一个连接
例如,解析html文件,当发现文件中存在资源文件的时候,这时候又创建单独的链接
最终导致,一个html文件的访问包含了多次的请求和响应,每次请求都需要创建连接、关系连接
这种形式明显造成了性能上的缺陷
如果需要建立长连接,需要设置一个非标准的Connection字段 Connection: keep-alive
4.2. HTTP1.1
在HTTP1.1中,默认支持长连接(Connection: keep-alive),即在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟
建立一次连接,多次请求均由这个连接完成
这样,在加载
html文件的时候,文件中多个请求和响应就可以在一个连接中传输
同时,HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间
同时,HTTP1.1在HTTP1.0的基础上,增加更多的请求头和响应头来完善的功能,如下:
- 引入了更多的缓存控制策略,如
If-Unmodified-Since,If-Match,If-None-Match等缓存头来控制缓存策略 - 引入
range,允许值请求资源某个部分 - 引入
host,实现了在一台WEB服务器上可以在同一个IP地址和端口号上使用不同的主机名来创建多个虚拟WEB站点
并且还添加了其他的请求方法:put、delete、options...
4.3. HTTP2.0
HTTP2.0在相比之前版本,性能上有很大的提升,添加了如下特性
- 多路复用
- 二进制分帧
- 首部压缩
- 服务器推送
4.3.1 多路复用
HTTP/2 复用 TCP 连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应,这样就避免了”队头堵塞”
上图中,可以看到第四步中css、js资源是同时发送到服务端
4.3.2 二进制分帧
帧是HTTP2通信中最小单位信息
HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x的文本格式,解析起来更高效
将请求和响应数据分割为更小的帧,并且它们采用二进制编码
HTTP2中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流
每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装,这也是多路复用同时发送数据的实现条件
4.3.3 首部压缩
HTTP/2在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键值对,对于相同的数据,不再通过每次请求和响应发送
首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新
例如:下图中的两个请求, 请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销
4.3.4 服务器推送
HTTP2引入服务器推送,允许服务端推送资源给客户端
服务器会顺便把一些客户端需要的资源一起推送到客户端,如在响应一个页面请求中,就可以随同页面的其它资源
免得客户端再次创建连接发送请求到服务器端获取
这种方式非常合适加载静态资源
4.4. HTTP3.0
我们都知道,HTTP是应用层协议,应用层产生的数据会通过传输层协议作为载体来传输到互联网上的其他主机中,而其中的载体就是 TCP 协议,这是 HTTP 2 之前的主流模式。
但是随着 TCP 协议的缺点不断暴露出来, HTTP 3.0 毅然决然切断了和 TCP 的联系,转而拥抱了 UDP 协议,这么说不太准确,其实 HTTP 3.0 其实是拥抱了 QUIC 协议,而 QUIC 又被叫做快速 UDP 互联网连接,QUIC的一个特征就是快。
QUIC 具有下面这些优势
- 使用
UDP协议,不需要三次连接进行握手,而且也会缩短TLS建立连接的时间。 - 解决了队头阻塞问题。
- 实现动态可插拔,在应用层实现了拥塞控制算法,可以随时切换。
- 报文头和报文体分别进行认证和加密处理,保障安全性。
- 连接能够平滑迁移。
4.5. 总结
HTTP 1.0:
- 浏览器与服务器只保持短连接,浏览器的每次请求都需要与服务器建立一个
TCP连接。
HTTP 1.1:
- 引入了长连接,即
TCP连接默认不关闭,可以被多个请求复用 - 引入
pipelining管道技术,在同一个TCP连接里面,客户端可以同时发送多个请求,但有队头阻塞问题。 - 新增了一些请求方法
- 新增了一些请求头和响应头
HTTP 2.0:
- 采用二进制格式而非文本格式
- 多路复用
TCP连接,在一个链接上客户端或服务器可同时发送多个请求或响应,避免了队头阻塞问题(只解决粒度级别为http request的队头阻塞) - 使用报头压缩,降低开销
- 服务器推送
HTTP 3.0:
-
利用
QUIC作为底层支撑协议,其融合UDP协议的速度、性能与TCP的安全可靠。 -
彻底解决了队头阻塞问题
-
连接建立更快
-
支持连接迁移