🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## 1\. `Http`到底是什么? `Http`翻译过来就是超文本传输协议,它的主要作用就是在客户端与服务端之间进行通信 我们平常在浏览器查看网页时就用到了`Http`协议,根据浏览器地址栏中指定的`URL`,`Web`浏览器从`Web`服务器端获取文件资源(`resource`)等信息,从而显示出 `Web` 页面。 `Http`协议主要具有以下特点 * 无连接:每一次请求都要连接一次,请求结束就会断掉,不会保持连接 * 无状态:每一次请求都是独立的,请求结束不会记录连接的任何信息,减少了网络开销,这是优点也是缺点 * 灵活:通过`http`协议中头部的`Content-Type`标记,可以传输任意数据类型的数据对象(文本、图片、视频等等),非常灵活 * 简单快速:发送请求访问某个资源时,只需传送请求方法和`URL`就可以了,使用简单,正由于`http`协议简单,使得`http`服务器的程序规模小,因而通信速度很快 当然`Http`协议也有一些缺点 * 无状态:请求不会记录任何连接信息,没有记忆,就无法区分多个请求发起者身份是不是同一个客户端的,意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大 * 明文传输:`Http`报文使用明文传输,如果在通信的过程中存在中间人,可以轻易的获取请求的所有内容 * 队头阻塞:当开启长连接时,多个`Http`请求复用一个`TCP`连接,同一时刻只能处理一个请求,那么当前面的请求耗时过长时,其他请求就只能处于阻塞状态 ## 2\. `Http`协议为什么是无状态的? 上面我们介绍了`Http`协议是无状态的,即每次请求都是独立的,服务端中不保存客户端的状态 因此为了区分用户的身份,我们需要每次都在`Header`中携带身份信息(比如`Cookie`),这样其实导致了每次连接传送的数据量变大了不少。 **那么为什么`Http`要这样设计呢?** 1. `http`最初设计成无状态的是因为只是用来浏览静态文件的,无状态协议已经足够,也没什么其他的负担。 2. 随着`web`的发展,它需要变得有状态,但是不是就要修改`http`协议使之有状态呢?是不需要的。因为我们经常长时间逗留在某一个网页,然后才进入到另一个网页,如果在这两个页面之间维持状态,代价是很高的。 3. 其次,老版本`http`是无状态的,但是现在对`http`提出了新的要求,按照软件领域的通常做法是,兼容历史版本,在`http`协议上再加上一层实现我们的目的。所以引入了`cookie`、`session`等机制来实现这种有状态的连接。 4. 同时,保存用户状态是一个很复杂的过程,而`Http`协议为了更快地处理大量事务,确保协议的可伸缩性,故意把`HTTP`协议设计的比较简单。因此没有必要在`Http`协议中引入状态管理 ## 3\. 什么是队头阻塞问题? `Http1.0`是无连接的,即每个请求/应答客户与服务器都要新建一个连接,完成之后立即断开连接 在`Http1.1`中引入了`Keep-Alive`支持长连接,即多个`Http`请求复用一个`TCP`连接,如下图所示: ![](https://img.kancloud.cn/de/8f/de8f6f10f2258eaba2c11ffec859564e_616x472.png) 如上所示,使用长连接,可以减少`TCP`握手时间,提高请求速度 但是在长连接下同样`Http`协议同样会有队头阻塞问题,因为我们虽然可以复用`TCP`连接,但`Http`请求仍然是串行的 > 请求1 -> 响应1 -> 请求2 -> 响应2 -> 请求3 -> 响应3 如上所示,就是这样一个先进先出的串行队列,没有轻重缓急的优先级,只有入队的先后顺序,排在最前面的请求最先处理,就导致如果队首的请求耗时过长,后面的请求就只能处于阻塞状态,这就是队头阻塞问题 当然我们也可以通过一些方式缓解这个问题 1. 一个域名允许分配多个长连接,就相当于增加了任务队列,不至于一个队列里的任务阻塞了其他全部任务。现在的浏览器标准中一个域名并发连接可以有`6~8`个(`Chrome`6个/`Firefox`8个) 2. 一个域名最多可以并发`6~8`个,那我们可以使用多个二级域名,当我们访问服务端时,可以让不同的资源从不同的二域名中获取,而它们都指向同一台服务器,这样能够并发更多的长连接了,从而减少队头阻塞 ## 4\. `GET`,`POST`,`PUT`等方法有什么区别? ### 4.1 `GET`与`POST`的区别 1. `GET` 用于获取信息,是无副作用的,是幂等的,且可缓存. 2. `POST` 用于修改服务器上的数据,有副作用,非幂等,不可缓存 其实`GET`与`POST`的区别主要就是这些,网上有些文章说`GET`的`URL`长度有限制,`HTTP` 协议没有`Body` 和 `URL` 的长度限制,对 `URL` 限制的大多是浏览器和服务器的原因。 浏览器原因就不说了,服务器是因为处理长`URL`要消耗比较多的资源,为了性能和安全(防止恶意构造长`URL`来攻击)考虑,会给`URL`长度加限制。 ### 4.2 `PUT`与`POST`的区别 有人说,`PUT`与`POST`的区别在于`POST`是用来创建数据的,`PUT`是用来更新数据的. 其实`PUT`与`POST`都能创建数据,它们的主要区别是`PUT`是幂等的,而`POST`不是幂等的 因此`PUT`能用于更新数据,也能用于创建数据,而`POST`只能用于创建数据 如果`POST`两条相同的数据,则会创建两条数据 而`PUT`两条相同的数据,则只会创建一条数据 ## 5\. 为什么引入`Https`? 上面说到了`HTTP`是明文传输的,在安全方面主要有以下缺点 1. `Http`通信使用明文(不加密),内容可能会被窃听 2. 不验证通信方的身份,因此有可能遭遇伪装 3. 无法证明报文的完整性,所以有可能已遭篡改 正因此才推出了`Https`协议来保证`Client`和`Server`交流的信息不能被其它第三方窃听及防止篡改与伪装 `Https`通信的主要过程如图所示: ![](https://img.kancloud.cn/7c/ec/7cec74d06aab92a234ebcb02b8e65eab_943x670.png) 主要做了以下几件事 1.客户端&服务端通信,协商加密方式 2.客户端(`Client`)和服务端(`Server`)互相确认身份 3.双方安全地交换`https`通信使用的密钥(`Session Key`) ## 6\. 为什么引入`Http2.0`? 上面我们已经介绍了`Http`协议的主要缺点 1.请求 / 响应头部(`Header`)未经压缩就发送,首部信息越多延迟越大。 2.发送冗长的首部。每次互相发送相同的首部造成的浪费较多; 3.服务器是按请求的顺序响应的,如果服务器响应慢,会招致客户端一直请求不到数据,也就是队头阻塞; 4.没有请求优先级控制; 5.请求只能从客户端开始,服务器只能被动响应 `Http2.0`正是为了解决以上问题才被引入的,相比`Http1.1`,`Http2.0`主要有以下改进 ### 6.1 头部压缩 `HTTP/2` 会压缩头(`Header`)如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复的部分。 这就是所谓的`HPACK`算法:在客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就提高速度了 ### 6.2 多路复用 #### 6.2.1 二进制分帧 `HTTP/2` 不再像`HTTP/1.1`里的纯文本形式的报文,而是全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧(`frame`):头信息帧和数据帧。 ![](https://img.kancloud.cn/9f/aa/9faaab9886c7fceb69f99d0366c230dc_500x275.png) 这样虽然对人不友好,但是对计算机非常友好,因为计算机只懂二进制,那么收到报文后,无需再将明文的报文转成二进制,而是直接解析二进制报文,这增加了数据传输的效率 #### 6.2.2 多路复用解决队头阻塞 原来`Headers + Body`的报文格式如今被拆分成了一个个二进制的帧,用`Headers`帧存放头部字段,`Data`帧存放请求体数据。 分帧之后,服务器看到的不再是一个个完整的 `HTTP` 请求报文,而是一堆乱序的二进制帧。 通信双方都可以给对方发送二进制帧,这种二进制帧的双向传输的序列,也叫做流(`Stream`)。 `HTTP/2` 用流(`Stream`)来在一个 `TCP` 连接上来进行多个数据帧的通信,这就是多路复用的概念。 这些二进制帧不存在先后关系,因此也就不会排队等待,也就没有了 `HTTP` 的队头阻塞问题。 举例来说,在一个 `TCP` 连接里,服务器收到了客户端 `A` 和 `B` 的两个请求,如果发现 `A` 处理过程非常耗时,于是就回应 `A` 请求已经处理好的部分,接着回应 `B` 请求,完成后,再回应 `A` 请求剩下的部分。 ![](https://img.kancloud.cn/a4/9b/a49b42b1d0aeb919373c64df6aa1bce9_371x381.png) ### 6.5 服务器推送 `HTTP/2` 还在一定程度上改善了传统的`「请求 - 应答」`工作模式,服务不再是被动地响应,也可以主动向客户端发送消息。 举例来说,在浏览器刚请求 `HTML` 的时候,就提前把可能会用到的 `JS`、`CSS` 文件等静态资源主动发给客户端,减少延时的等待,也就是服务器推送 ## 7\. 为什么引入`Http3.0`? `Http2.0`还没学,怎么`Http3.0`又来了? 总得来说,这是因为`Http2.0`还存在一定的缺陷 `HTTP/2` 主要的问题在于,多个 `HTTP` 请求在复用一个 `TCP` 连接,下层的 `TCP` 协议是不知道有多少个 `HTTP` 请求的。 所以一旦发生了丢包现象,就会触发 `TCP` 的重传机制,这样在一个 `TCP` 连接中的所有的 `HTTP` 请求都必须等待这个丢了的包被重传回来。 `HTTP/2` 多请求复用一个`TCP`连接,一旦发生丢包,就会阻塞住所有的 `HTTP` 请求。 可以看出,这其实不是`Http`协议的问题,而是传输层协议的问题 所以 `HTTP/3` 把 `HTTP` 下层的 `TCP` 协议改成了 `UDP`! ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ac96cf13a30a423cb42e8ada49655ece~tplv-k3u1fbpfcp-watermark.awebp) `UDP` 发生是不管顺序,也不管丢包的,所以不会出现 `HTTP/1.1` 的队头阻塞 和 `HTTP/2` 的一个丢包全部重传问题。 大家都知道 `UDP` 是不可靠传输的,但基于 `UDP` 的 `QUIC` 协议 可以实现类似 `TCP` 的可靠性传输。 `QUIC` 是一个在 `UDP` 之上的伪 `TCP` + `TLS` + `HTTP/2` 的多路复用的协议,在这里就不详细介绍了,有兴趣的同学可参考:[QUIC协议连接过程介绍](https://link.juejin.cn?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F111716047 "https://zhuanlan.zhihu.com/p/111716047") 总得来说,`QUIC` 是新协议,对于很多网络设备,根本不知道什么是 `QUIC`,只会当做 `UDP`,这样会出现新的问题。 所以 `HTTP/3` 现在普及的进度非常的缓慢,大家只做简单了解即可。 ## 8\. 浏览器输入`url`后发生了什么? 这个是面试中的常见问题了,我们在了解了上面的知识点后,再一起来看下这个问题 要回答这个问题,我们需要对`TCP/IP`协议族有一定的了解 ### 8.1 `Tcp/IP`协议族 `TCP/IP` 协议族里重要的一点就是分层。 `TCP/IP` 协议族按层次分别分为以下 4 层:应用层、传输层、网络层和数据链路层。 把 `TCP/IP` 层次化是有好处的。比如,如果互联网只由一个协议统筹,某个地方需要改变设计时,就必须把所有部分整体替换掉。 而分层之后只需把变动的层替换掉即可。把各层之间的接口部分规划好之后,每个层次内部的设计就能够自由改动了。 值得一提的是,层次化之后,设计也变得相对简单了。 处于应用层上的应用可以只考虑分派给自己的任务,而不需要弄清对方在地球上哪个地方、对方的传输路线是怎样的、是否能确保传输送达等问题。 #### 8.1.1 应用层 应用层决定了向用户提供应用服务时通信的活动。 `TCP/IP` 协议族内预存了各类通用的应用服务。比如,`FTP`(`File Transfer Protocol`,文件传输协议)和 `DNS`(`Domain Name System`,域名系统)服务就是其中两类。 `HTTP` 协议也处于该层。 #### 8.1.2 传输层 传输层对上层应用层,**提供处于网络连接中的两台计算机之间的数据传输**。 在传输层有两个性质不同的协议:`TCP`(`Transmission ControlProtocol`,传输控制协议)和 `UDP`(`User Data Protocol`,用户数据报协议)。 #### 8.1.3 网络层 网络层用来处理在网络上流动的数据包。数据包是网络传输的最小数据单位。 该层规定了通过怎样的路径(所谓的传输路线)到达对方计算机,并把数据包传送给对方。 与对方计算机之间通过多台计算机或网络设备进行传输时,**网络层所起的作用就是在众多的选项内选择一条传输路线**。 `IP`协议就在网络层 #### 8.1.4 数据链路层 **用来处理连接网络的硬件部分。** 包括控制操作系统、硬件的设备驱动、`NIC`(`Network Interface Card`,网络适配器,即网卡),及光纤等物理可见部分(还包括连接器等一切传输媒介)。 硬件上的范畴均在链路层的作用范围之内。 ### 8.2 浏览器输入`url`后大致流程 1. 解析用户输入的`Url` 2. 通过`DNS`协议根据域名查询`ip`地址 3. 客户端发起请求 4. 服务端接受请求并处理 5. 客户端接受响应 6. 浏览器渲染页面 这里我们主要关注客户端发起请求及服务端接受请求的过程,这里就用到了`TCP/IP`协议族 在发送数据时,每层都要对数据进行封装,在接收数据时,每层都要对数据进行解封,如下图所示: ![](https://img.kancloud.cn/17/2a/172a4652c0dc254b32205fe7c2f4e510_720x337.png) 简单来说,就是从应用层发`http`请求,到传输层通过三次握手建立`tcp`连接,再到网络层的`ip`寻址,再经过数据链路层与物理层,最后到达服务端。 然后服务端经过相反的过程,在每一层将数据取出来即可。 关于浏览器输入`url`后的流程我们这里没有讲得很详细,想要了解更多细节的同学可参考:[在浏览器输入 URL 回车之后发生了什么(超详细版)](https://link.juejin.cn?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F80551769 "https://zhuanlan.zhihu.com/p/80551769") ## 总结 本文主要梳理了`Http`协议相关知识点,并回答了以下问题 1. `Http`到底是什么? 2. `Http`协议为什么是无状态的? 3. 什么是队头阻塞问题? 4. `GET`,`POST`,`PUT`等方法有什么区别? 5. 为什么引入`Https`? 6. 为什么引入`Http2.0`? 7. 为什么引入`Http3.0`? 8. 浏览器输入`url`后发生了什么? 如果对您有所帮助,欢迎点赞,谢谢~ ### 参考资料 [20分钟助你拿下HTTP和HTTPS,巩固你的HTTP知识体系](https://juejin.cn/post/6994629873985650696 "https://juejin.cn/post/6994629873985650696") [Http协议为什么是无状态的](https://link.juejin.cn?target=https%3A%2F%2Fwww.byway.xyz%2Ftips%2Fhttp.html "https://www.byway.xyz/tips/http.html") [What is the difference between POST and PUT in HTTP?](https://link.juejin.cn?target=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F630453%2Fwhat-is-the-difference-between-post-and-put-in-http "https://stackoverflow.com/questions/630453/what-is-the-difference-between-post-and-put-in-http") [图解网络: HTTP 常见的面试题](https://link.juejin.cn?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F111716047 "https://zhuanlan.zhihu.com/p/111716047") [在浏览器输入 URL 回车之后发生了什么(超详细版)](https://link.juejin.cn?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F80551769 "https://zhuanlan.zhihu.com/p/80551769") 作者:程序员江同学 链接:https://juejin.cn/post/7001839784289108005 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。