Skip to content

计算机网络之 HTTP 协议  #3

Open
@myLightLin

Description

@myLightLin

HTTP 的全称是 HyperText Transfer Protocol,中文是超文本传输协议。它是一个应用层协议,底层使用 TCP 协议来传输,这就是说,在使用 HTTP 发起请求前,需要先建立 TCP 链接,也就是三次握手,然后才能传输数据。

HTTP 的发展历程

HTTP/0.9 & HTTP/1.0

1991 年发布了第一个版本 0.9,这个版本就是简单的 request-response 模式,只支持 GET 方法。后来在 1996 年发布了 1.0 版本,自此 HTTP 开始走向规范化,也是比较具书面意义的一个规范版本。主要特性有:

  • 请求行中增加了版本号,如 GET 200 /index.html HTTP/1.1
  • 增加了 HEAD, POST 等方法
  • 增加了响应状态码
  • 引入了 header 头部概念
  • 传输数据不再仅限文本,Content-Type 可以传输其它文件了

但是这个版本有个很大问题,每请求一次资源都要新建 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 的对比:
image

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

其中 GetPost 的区别有:

  • 从缓存的角度,get 可以被缓存,post 不会
  • 从编码角度,get 只能进行 url 编码,接收 ASCII 字符;post 没有限制
  • 从参数角度,get 请求参数在 url 中;而 post 则是放在 body 里
  • 从幂等性角度,get 是幂等的,post 是不幂等
  • 从 TCP 角度,get 会一次性把请求报文发送出去;而 post 则会分为两个 TCP 包,先发送 header 部分,如果服务器响应 100;再继续发送 body 部分

状态码主要有 1xx2xx3xx4xx5xx 几种
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/plain

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions