[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
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- Android
- 四大组件
- Activity
- Fragment
- Service
- 序列化
- Handler
- Hander介绍
- MessageQueue详细
- 启动流程
- 系统启动流程
- 应用启动流程
- Activity启动流程
- View
- view绘制
- view事件传递
- choreographer
- LayoutInflater
- UI渲染概念
- Binder
- Binder原理
- Binder最大数据
- Binder小结
- Android组件
- ListView原理
- RecyclerView原理
- SharePreferences
- AsyncTask
- Sqlite
- SQLCipher加密
- 迁移与修复
- Sqlite内核
- Sqlite优化v2
- sqlite索引
- sqlite之wal
- sqlite之锁机制
- 网络
- 基础
- TCP
- HTTP
- HTTP1.1
- HTTP2.0
- HTTPS
- HTTP3.0
- HTTP进化图
- HTTP小结
- 实践
- 网络优化
- Json
- ProtoBuffer
- 断点续传
- 性能
- 卡顿
- 卡顿监控
- ANR
- ANR监控
- 内存
- 内存问题与优化
- 图片内存优化
- 线下内存监控
- 线上内存监控
- 启动优化
- 死锁监控
- 崩溃监控
- 包体积优化
- UI渲染优化
- UI常规优化
- I/O监控
- 电量监控
- 第三方框架
- 网络框架
- Volley
- Okhttp
- 网络框架n问
- OkHttp原理N问
- 设计模式
- EventBus
- Rxjava
- 图片
- ImageWoker
- Gilde的优化
- APT
- 依赖注入
- APT
- ARouter
- ButterKnife
- MMKV
- Jetpack
- 协程
- MVI
- Startup
- DataBinder
- 黑科技
- hook
- 运行期Java-hook技术
- 编译期hook
- ASM
- Transform增量编译
- 运行期Native-hook技术
- 热修复
- 插件化
- AAB
- Shadow
- 虚拟机
- 其他
- UI自动化
- JavaParser
- Android Line
- 编译
- 疑难杂症
- Android11滑动异常
- 方案
- 工业化
- 模块化
- 隐私合规
- 动态化
- 项目管理
- 业务启动优化
- 业务架构设计
- 性能优化case
- 性能优化-排查思路
- 性能优化-现有方案
- 登录
- 搜索
- C++
- NDK入门
- 跨平台
- H5
- Flutter
- Flutter 性能优化
- 数据跨平台