# HTTP 协议

超文本传输协议(HyperText Transfer Protocol)是万维网中非常重要的基础,作为应用层协议,承担起了网络数据通信的绝大部分工作。

# 特点

  • 简单:基于请求-响应的模式,发起请求时只需指定请求方法(GET、POST)和路径
  • 灵活:支持不同格式的数据传输,具有非常多的可选字段
  • 无连接:每次连接只处理一个请求,降低资源消耗,可以同时服务多个客户端
  • 无状态:对事物处理无记忆能力,前一次请求和后一次没有相连关系,从而可以更快的应答

# 工作简要流程

  • 在发送 HTTP 请求之前,我们先建立 TCP 连接(三次握手)
  • 通过 TCP 套接字,客户端将 HTTP 请求发送给服务端,默认的 http 端口为 80
  • 服务端收到请求后进行解析,处理后将结果通过 TCP 套接字返还给客户端
  • 客户端收到数据后进行解析,将不同的内容以不同的形式进行显示或使用
  • 根据 connection 模式的不同,服务端会主动关闭 TCP 连接,或者维持该连接一段时间。

# 请求方法

HTTP/1.1 定义了八种方法以不同方式操作指定的资源:

方法 作用
GET 向指定资源发出获取请求。GET 应只用在读取数据上
HEAD 与 GET 类似,只保留 HTTP Header 不保留 Body,得到必要信息的同时节约带宽
POST 向指定资源提交数据,请求服务器进行处理
PUT 向指定资源位置上传其最新内容
DELETE 请求服务器删除 Request-URI 所标识的资源
TRACE 回显服务器收到的请求,主要用于测试或诊断
OPTIONS 返回该资源所支持的所有 HTTP 方法
CONNECT 用于代理服务器,让代理服务器代替用户去获取其他网页

其中,我们一般用户用的最多的就是 GET 请求与 POST 请求。

对于 GET、HEAD、POST 这三种请求,如果:

  • 没有添加自定义头(比如 token、Authentication)
  • Content-Typetext/plainmultipart/form-dataapplication/x-www-form-urlencoded 其中一种

该请求则被视为简单请求

而其他的请求(一般以 ajax 请求形式)就属于非简单请求了。

# GET 与 POST 的区别

方面 GET POST
定义 从指定的资源请求数据 向指定的资源提交要被处理的数据
用途 一般用于获取资源,不应该去修改资源 更多用于提交表单,处理敏感数据
提交数据 将附带的数据以键值对的形式加在 URL 末尾实现的(以?开头),有数据长度的限制 将附带的数据以键值对的形式加在 HTTP Body 中发送,对数据长度没有要求
缓存 能够被浏览器缓存,可以存为书签、有历史记录 不行
安全 请求的数据暴露在 URL 中,任何人都能看到,安全性较差 请求数据不显示于 URL,且不会被浏览器或服务器缓存,安全性相对较好
幂等 我们一般要求它符合幂等性 一般不具幂等性

幂等性即多次操作与单次操作得到的结果都是相同的,好似“1 的三次方仍然等于 1”一样。


# 状态码

状态码 类别 解释
1XX Informational(信息) 接收的请求正在处理
2XX Success(成功) 请求正常处理完毕
3XX Redirection(重定向) 需要进行附加操作以完成请求
4XX Client Error(客户端错误) 服务器无法处理请求
5XX Server Error(服务器错误) 服务器处理请求出错

常见的一些状态码:

状态码 类别 解释
200 OK 客户端请求成功
301 Moved Permanently 永久重定向。浏览器会自动定向到返回信息里的新 URI
302 Found 临时重定向。与 301 类似,但资源只是临时被移动
304 Not Modified 所请求的资源未修改,可以复用协商缓存
400 Bad Request 客户端请求有语法错误,不能被服务器所理解
401 Unauthorized 请求未经授权,请求要求用户身份认证
403 Forbidden 服务器收到请求,但是拒绝提供服务
404 Not Found 请求资源不存在(如输入了错误的 URL)
500 Internal Server Error 服务器内部发生不可预期的错误
503 Server Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求

# 版本

比较常提到的 HTTP 协议版本一般有 1.0、1.1、2.0。

# HTTP/1.0

HTTP/1.0 在设计时,为了提高服务器系统的响应效率,规定浏览器与服务器只保持短暂的连接,每次 HTTP 请求都要与服务器建立一次 TCP 连接,并在请求结束后断开该连接。

但随着网络的发展,网页变得越来越复杂,很快 HTTP/1.0 就更不上时代了。因为对于一个网页,客户端往往需要多次请求才能完整地显示它(比如存在图片等其他资源),而 TCP 连接的无法复用使得每次 HTTP 请求都得经历三次握手、慢启动的过程,反而使开销增大。

于是很快,HTTP/1.1 版本出现了。


# HTTP/1.1

HTTP/1.1 很大的一个特点就是支持持久连接(且为默认值)。在一个 TCP 连接上我们可以多次发起 HTTP 请求并得到响应,减少了建立和关闭连接的消耗和延迟。

在 HTTP/1.1 中,我们使用 Connection 请求头字段作为连接的持久性的设置。使用 keep-alive 则为默认的长连接,而 close 则表明自己并不想维持长连接。

除此以外,HTTP/1.1 还增加了一些其他功能:

  • Cache 缓存使用 ETagIf-None-Match 的新字段,解决了旧字段的误差、精度、性能问题
  • Host 请求头字段,允许服务器在相同 ip 地址与端口号的情况下配置不同的 web 站点
  • 通过指定 RANGE:bytes=XXXX,实现文件从 XXXX Bytes 开始的断点续传
  • ...

# HTTP/2.0

HTTP/1.1 在各方面而言做的都还不错,所以一直没有推出新版本。不过随着网络的继续发展,我们开始更加关注 HTTP 协议的性能,想要在其中取得更加好的效果。

我们能够发现 HTTP/1.1 有着这些缺点:

  • 虽然 1.1 通过管道技术实现一次性发送多个请求,但如果出现队头阻塞(即第一个请求阻塞),后面的请求也得跟着等待
  • 只能由客户端单向发起请求
  • 无记忆性使得报文头信息冗余量大
  • 通过文本传输,数据未压缩

于是 HTTP/2.0 针对性能提出了几个优化特性:

# 二进制分帧

原来的纯文本传输非常的直白简单,但是由于文本的多样性,在解析和拓展上比较麻烦。而 HTTP/2.0 最大的特点就是采用二进制的形式传输数据,从而为后续的优化提供了更大的空间。

HTTP/2.0 中,数据以消息的形式发送,而一个消息可以被分为多个帧,每一帧的首部都有流标识,从而允许每个帧乱序发送,收到之后再进行组装。

# 多路复用

在 HTTP/1.X 中,因为队头阻塞机制,多请求并发发送需要使用多个 TCP 连接,每个 TCP 连接还要握手、慢开始,且会受到浏览器单域名并发连接上限的限制(6~8 个)。

而在 HTTP/2.0 中,所有请求都复用一个 TCP 连接,通过帧的标识就可以知道该帧属于哪一个请求,从而大大提高性能。

不过,多路复用只解决了 HTTP 的队头阻塞问题,而 TCP 队头阻塞的问题仍然存在,这是传输层层面导致的结果。

# 首部压缩

由于多个 HTTP 请求之间往往会有较多的重复头信息,HTTP/2.0 采用了首部压缩的方式(例如 HPACK 压缩格式),在服务器与客户端两边同时维护一个索引表,对于已经出现过的头信息,将其保存为 value,后续只需传输更短的 key,另一端收到后即可还原为 value。

# 服务端推送

在 HTTP/2.0,我们允许服务器在收到客户端的请求后,主动地推送其他资源。

按照原本的流程,如果客户端获取一份 HTML 文档,只有在进行预解析后才会发起新的请求去获得关联的文件;而服务端推送机制则可以将这些文件与 HTML 文档一起发送给客户端,从而减少一定的延迟。


上次更新: 2024/3/24 16:13:56