计算机网络之 HTTP 协议
HTTP 的全称是 HyperText Transfer Protocol,中文是超文本传输协议。它是一个应用层协议,底层使用 TCP 协议来传输,这就是说,在使用 HTTP 发起请求前,需要先建立 TCP 链接,也就是三次握手,然后才能传输数据。
HTTP 的发展历程
HTTP/0.9 & HTTP/1.0
0.9 版本发布于 1991 年,1.0 版本发布于 1996 年。这两个版本就是简单的 request-response 模式,其中 0.9 版本只支持 GET 方法,后来 1.0 版本进行了一些扩展,增加了:
- 请求行中增加了版本号,如
GET 200 /index.html HTTP/1.1
- 增加了 HEAD, POST 等方法
- 增加了响应状态码
- 引入了 header 头部概念
- 传输数据不再仅限文本,Content-Type 可以传输其它文件了
HTTP1.0 可以说是比较书面意义的一份规范,让 HTTP 更加规范化了,但是这个版本有个很大问题,每请求一次资源都要新建 TCP 连接,而且是串行请求。
HTTP/1.1
HTTP/1.1 发布于 1999 年,在 1.0 的基础上,解决了一些网络性能问题,另外增加了新特性:
- 持久链接:通过设置
keep-alive
来重用 TCP 连接 - 支持 pipeline 网络传输,第一个请求发出了,可以接着发第二个请求出去
- 增加了 Cache-Control 缓存控制
- 协议头注增加了 Language, Encoding, Type 等
- 数据分块传输,这是因为如果页面内容是动态生成的,浏览器不知道何时才能接收完毕,于是服务器将数据分割成多个 chunk,每次发送时附上上次数据块的长度,最后通过发送零长度的块作为数据发送完毕的标志
- 强制要求 host 头,以便让服务器知道要请求哪个网站,因为存在多个域名解析到同一个 ip 上,要区分具体域名
- 增加了 PUT、DELETE、OPTIONS 等方法,其中 OPTIONS 常用于 CORS
- 引入了客户端 cookie
HTTP/2
了解 HTTP/2 之前,先看 HTTP/1.1 还有哪些缺点:
- HTTP/1.1 还是存在性能问题,虽然可以重用 TCP 链接了,但是请求还是串行发的,需要保证接收顺序
- HTTP/1.1 传输数据还是以文本的方式,传输成本较高
- HTTP/1.1 pipeline 时,如果有一个请求 block 了,那队列后的请求也统统被阻塞住了,这就是队头阻塞问题
所以在 2010 年的时候,Google 就在搞一个实验型的协议:SPDY。这个协议后来成为了 HTTP/2 的基础,HTTP/2 发布于 2015 年,它带来了许多新的特性:
- 采用二进制编码,利于提高传输效率
- 多路复用,可以在一个 TCP 链接中并发多个 HTTP 请求,解决了 1.1 的串行请求问题。具体就是通过帧和流
- 压缩请求头,采用 HPACK 算法。两端都维护一个动态的字典表来分析请求头中哪些是重复的
- 服务端 push 技术,主动推送一些用得到的内容放在客户端缓存里
- 安全性提升,加密通信要求 TLS 至少是 1.2 版本
以下是 HTTP/2 与 HTTP/1.1 的对比:
HTTP/3
黑客的世界就是不断的折腾,HTTP/2 看起来已经完美了,但还是存在问题:多个 HTTP 请求在复用一个 TCP 链接,如果发生丢包,那所有的 HTTP 请求都必须等待这个被丢了的包重传回来,这还是存在队头阻塞问题,只不过现在是 TCP 的问题。
那既然 TCP 有问题,就干脆放弃掉它!所以 Google 另起炉灶搞了个 QUIC,它抛弃了 HTTP 底层的 TCP,改用 UDP。后台这个协议又又成为了 HTTP/3 的基础。HTTP/3 发布于 2018 年,它的特性如下:
- 使用 UDP 协议作为底层,自然解决了 HTTP/2 的阻塞问题
- 在 UDP 的基础上,又加入了 TCP 的丢包重传和拥塞控制功能
- 换成 UDP 后,直接把 TCP 的三次握手和 TLS 的三次握手合并了,原先是六次网络交互,现在只需三次
可以说,HTTP/3 是在 UDP 上组合了 TCP + TLS + HTTP/2 的功能,由于动了底层协议,它离大规模应用还很遥远。
HTTP 请求的结构
HTTP 是基于客户端-服务器模型的,客户端发送请求,服务端响应请求。请求和响应都由以下部分组成:
- 请求行/响应行
- 头部(Header)
- 主体内容(Body)
请求行
包含请求方法、状态码、路径和版本,如 GET 200 /index.html HTTP/1.1
请求方法包含:
GET
POST
HEAD
PUT
DELETE
OPTIONS
CONNECT
TRACE
其中 Get
和 Post
的区别有:
- 从缓存的角度,get 可以被缓存,post 不会
- 从编码角度,get 只能进行 url 编码,接收 ASCII 字符;post 没有限制
- 从参数角度,get 请求参数在 url 中;而 post 则是放在 body 里
- 从幂等性角度,get 是幂等的,post 是不幂等
- 从 TCP 角度,get 会一次性把请求报文发送出去;而 post 则会分为两个 TCP 包,先发送 header 部分,如果服务器响应 100;再继续发送 body 部分
状态码主要有 1xx
, 2xx
, 3xx
, 4xx
, 5xx
几种
1 xx:请求接收,继续处理
- 100:请求已被接收,可以继续发送
- 101:从 HTTP 升级为 websocket ,如果服务器同意变更,返回 101
- 103:客户端应该在服务器返回 HTML 前开始预加载资源
2xx:成功
- 200:请求成功
- 204:与 200 一样,但响应没有 body
- 206:返回部分内容,它的使用场景是分块,断点续传(content-range)
3xx:重定向相关
- 301:永久重定向,比如域名换了
- 302:临时重定向
- 304:资源未修改,可使用协商缓存
- 307:临时重定向,与 302 区别在于不允许将原本为 POST 的请求重定向到 GET 请求上
4xx: 客户端错误
- 401:未进行身份认证
- 403:无权限,禁止访问
- 404:资源不存在
- 405:请求方法不被允许
5xx: 服务器错误
- 500:服务器错误
- 502:网关或代理出现错误
- 503:服务不可达
- 504:网关超时
请求头
包含 request header 和 response header。这里列举几个常见的头部字段:
- Content-Type
- Content-Length
- User-Agent
- Host
- accept
- accept-encoding
- cookie
请求 body
常见 body 格式:
- application/json
- application/x-www-form-urlencoded
- multipart/form-data 文件上传
- text/xml
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

上一篇: 小程序的双线程模型
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论