身为一个前端,HTTP 对我而言就像是云雾环绕的一座山,看不透也不知从哪开始攀登。深入学习 HTTP 协议系列就是我对罗剑锋老师的《透视 HTTP 协议》所做的总结。希望能对大家的登山之旅有所帮助。

当我们在浏览器地址栏输入网址再按下回车发生了什么?

  1. 浏览器发起域名解析获取地址对应的 IP;
  2. 浏览器用 TCP 的三次握手与服务器建立连接;
  3. 浏览器向服务器发送拼好的报文;
  4. 服务器收到报文后处理请求,同样拼好报文再发给浏览器;
  5. 浏览器解析报文,渲染输出页面。

域名解析的过程中有多级缓存,浏览器先查看自身缓存,没有再向操作系统缓存要,还没有就检查本机域名解析文件 hosts,最后则会用 DNS 域名解析系统进行。在这个过程中可能会经历 CDN 解析,拿到 CDN 服务器的地址

在达到目标服务器后,通常会经历负载均衡设备,负载均衡设备会访问系统里的缓存服务器,通常有 memory 级缓存 Redis 和 disk 级缓存 Varnish。

如果缓存服务器里没有所要数据,就会把请求转发给应用服务器,例如 Java 的 Tomcat/Netty/Jetty,Python 的 Django,还有 PHP、Node.js、Golang 等等。然应用服务器处理完成后把执行的结果返回给负载均衡设备。

到达负载均衡后请求的处理就完成了,会按照请求顺序原路返回。

HTTP 协议的核心部分 - HTTP 报文

报文结构

HTTP 协议的请求报文和响应报文的结构由三大部分组成

  1. 起始行(start line):描述请求或相应的基本信息;
  2. 头部字段集合(header):key-value 的形式;
  3. 消息正文(entity):实际传输数据。

其中前两部分经常被称为 请求头/响应头,正文部分称为body

HTTP 协议规定报文必须有 header,可以没有 body,在 header 和 body 之间必须有一个空行,如下图所示。

报文结构

抓包分析

抓包分析

图中 1,第一行为请求行部分。2,为 header 部分,3 是空白行部分。这里没有发送 body,所以没有 body 信息。

请求行

报文的起始行就是请求行,它简要的描述了客户端想要如何操作服务器端的资源。

1
GET / HTTP / 1.1;

在抓包获取的信息中,我们可以看到请求头由三部分组成:

  1. 请求方法,表示对资源的操作,对应上面代码中的 GET,;
  2. 请求目标,通常是一个 URI,表记录请求方法要操作的资源,对应 /
  3. 版本号:表示报文使用的 HTTP 协议版本,对应 HTTP/1.1

这三个部分通常用空格来分隔,最后用 CRLF 换行表示结束,用图片来描述就是下面这个方式。

请求行

状态行

服务器响应报文里的起始行叫做状态行,表示服务器响应的状态

1
2
HTTP/1.1 200 OK
HTTP/1.1 404 Not Found

也由三部分组成:

  1. 版本号,表示报文使用的 HTTP 协议版本号;
  2. 状态码,表示处理结果,如 200 成功,500 服务器错误;
  3. 原因:作为数字状态码的补充,在上面代码是 OK

它的组成规则和请求行一致,用空格来分隔,用 CRLF 换行表示结束,如下图所示。

状态行

头部字段(header)

请求行/状态行加上头部字段(header),就组成了请求头/响应头。
如下图所示:

请求头/响应头

头部字段是 key-value 的形式,之间用 分隔,最后用 CRLF 换行表示结束。

注意:

  1. 字段不区分大小写,不允许出现下划线_,可以使用短横线-连接。
  2. key 后面紧跟:,不能有空格。但是:和 value 之间可以出现空格。
  3. 字段的顺序是无意义的。
  4. 字段原则上不能出现重复,除非字段本身语义允许,如 Set-Cookie。
  5. 在请求头/响应头中只有 Host 字段是必须的。

HTTP 请求方法

标准请求方法

  1. GET:获取资源,可以理解为读取或者下载数据;
  2. HEAD:获取资源的元信息;POST:向资源提交数据,相当于写入或上传数据;
  3. PUT:类似 POST;DELETE:删除资源;
  4. CONNECT:建立特殊的连接隧道;
  5. OPTIONS:列出可对资源实行的方法;
  6. TRACE:追踪请求 - 响应的传输路径。

请求分类

常用方法

GET 和 HEAD

GET 的含义是从服务器获取资源,可以搭配 URI 和其他头部字段实现对资源更精细的操作。

HEAD 的含义与 GET 类似,都是从服务器获取资源,服务器处理机制也一样,但服务器不会返回请求的实体数据,只会传回响应头,也就是资源的“元信息”。可以将他看做 GET 的简化版。

POST 和 PUT

POST 和 PUT 是指向 URI 指定资源提交数据,而 POST 和 PUT 的区别在于 POST 意味着“新建”,PUT 则是 “修改”。

其他方法

DELETE:指示服务器删除资源。
CONNECT:要求服务器为客户端和另一台远程服务器建立一条通道,浏览器充当代理角色。
OPTIONS:要求服务器列出可对资源实行的请求方法。
TRACE:用于对 HTTP 链路的测试或诊断。

安全和幂等

安全在 HTTP 协议里是指请求方法不会修改服务器上的资源。所以只有 GET 和 HEAD 是安全的,因为它们对资源进行是只读操作。

幂等意思是多次执行相同操作,结果也都是相同的,即多次“幂”后“相等”。

可以看出 GET 和 HEAD 既是安全的也是幂等的,DELETE 是幂等的,POST 和 PUT 既不安全也不幂等。

URI 与 网址

URI:统一资源标识符,包括 URL 和 URN 两部分。
URL:统一资源定位符,就是我们俗称的“网络地址”,因为 URL 十分普遍,所以通常用 URL 表示 URL 或 URI。

URL 格式

URL 本质上是一个字符串,它的作用是 唯一的标记资源的位置或者名字。它不仅能标记万维网资源,还能标记动态服务资源或者本地资源。

它的组成部分如下图所示:由 scheme、host:port、path 和 query 组成。

URL 格式

URI 的第一个组成部分是 scheme 代表协议名,表示资源应该用那种协议访问(如:http、ftp、file)。

scheme 之后就是固定的三个字符“**://**”,用来把 scheme 和后面的部分分离开。

“**://”之后是 **authority 部分,表示资源所在的主机名,通常形式是 host:port ,即主机名加端口号。主机名必须要有,可以是 IP 地址或域名。端口号可以省略,浏览器等客户端会根据 scheme 使用默认的端口号,例如 HTTP 默认的是 80,HTTPS 默认的是 443。

path 是用来标记资源所在位置。path 采用的是类似路径的表示方式,URI 的 path 必须要以 “/” 开始。

看下面这个例子

1
https://tools.ietf.org/html/rfc7230

https 是 scheme,表示使用的是 https 协议,tools.ietf.org 就是主机名,这里默认访问端口号是 443,路径就是后面的 /html/rfc7230

URI 的查询参数 query

在上图 URL path 后还有一个 query 部分,query 由一个“?”开始,但不包含“?”,表示对资源附加的额外要求。

query 的格式是由 多个 “key=value” 组成,多个 “key=value” 之间用 “&” 连接。

URI 的编码

URI 中只能使用 ASCII 码,对于英语以外的汉语、日语及其他字符 URI 会对他们进行 encodeURI 转义。

转义规则是,把字符(unicode)编码成 utf-8,utf-8 是用 1-4 个字节表示的,所以每个字节转换成 16 进制并在前面用百分号(%)连接,最后并把每个字节转换的结果连接起来。

响应状态码

五类状态码

RFC 标准把状态码分成了以下五类

  • 1××:提示信息,表示目前是协议处理的中间状态,还需要后续的操作;
  • 2××:成功,报文已经收到并被正确处理;
  • 3××:重定向,资源位置发生变动,需要客户端重新发送请求;
  • 4××:客户端错误,请求报文有误,服务器无法处理;
  • 5××:服务器错误,服务器在处理请求时内部发生了错误。

常见响应状态码及含义

  • 1xx
    • 101 Switching Protocols,客户端要求服务端改成其他协议继续通信,如果服务器统一变更协议,就会返回状态码 101.
  • 2xx
    • 200 OK,表示请求成功,通常在响应头后会有 body 数据。
    • 204 No Content,也表示请求成功,它与 200 的区别在于,响应头后没有 body 数据。
    • 206 Partial Content,常见于获取请求资源的部分数据。“Content-Range”,表示 body 里返回数据的具体范围。
  • 3xx
    • 301 Moved Permanently,表示永久重定向。
    • 302 Found,表示临时重定向,浏览器不会对临时重定向的内容做缓存优化。
    • 304 Not Modified,缓存重定向,用户缓存控制,URL 不包含跳转含义。
  • 4xx
    • 400 Bad Request,表示请求错误。
    • 403 Forbidden,表示服务器禁止访问资源。
    • 404 Not Found,表示资源在服务器上未找到。
  • 5xx
    • 500 Internal Server Error,表示服务器发生错误,是一个较通用的错误码。
    • 502 Bad Gateway,表示服务器禁止访问资源。
    • 503 Service Unavailable,表示服务器正忙,暂时无法响应。

HTTP 的特点和优缺点

五大特点

  1. HTTP 是灵活可扩展的,可以任意添加头字段实现任意功能;
  2. HTTP 是可靠传输协议,基于 TCP/IP 协议“尽量”保证数据的送达;
  3. HTTP 是应用层协议,比 FTP、SSH 等更通用功能更多,能够传输任意数据;
  4. HTTP 使用了请求 - 应答模式,客户端主动发起请求,服务器被动回复请求;
  5. HTTP 本质上是无状态的,每个请求都是互相独立、毫无关联的,协议不要求客户端或服务器记录请求相关的信息。

优缺点

  • 优点:

    • 灵活可拓展;
    • 应用广泛,环境成熟;
    • 无状态,不需要额外资源来记录路状态信息,减轻服务器负担;
    • 明文传输,数据可直接查看到,方便开发调试。
  • 缺点:

    • 无状态,每次访问都要获取一遍身份信息;
    • 明文传输,数据容易被截取;
    • 不安全,数据在传输过程中容易被篡改。