HTTP——篇①
写在前面
-
这是HTTP的第一篇【HTTP的基础篇】
主要是不想让文章太长了。【不想写 + 不想看】
-
欢迎讨论【补充内容 or 更正错误】
-
本文很多观点都是从RFC中理解的。
一、HTTP简介与演变过程
- 简介
超文本传输协议(英语:Hyper Text Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是 万维网 的数据通信的基础。设计HTTP最初的目的是为了提供一种发布和接收 HTML 页面的方法。通过HTTP或者HTTPS协议请求的资源由统一资源标识符URI 来标识。
-
版本变迁
-
HTTP / 0.9 【1991年】
一开始的HTTP的主要目的是为了能够获取文本数据或者超文本的数据。很单一,仅仅有GET方法,并且没有消息头[ 请求头 / 响应头 ],无法向服务器传递太多东西。
-
HTTP / 1.0 【1996年】
时代在发展,HTTP也升级了,支持了 POST、HEAD等方法。这个时候数据类型就不在局限与文本数据了。并且有了消息头 [ 请求头 / 响应头] 。但是最大的痛点是在 每一个请求,都需要三次握手【与服务器建立TCP连接】。请求处理完成后,还要四次挥手【与服务器断开TCP连接】
-
HTTP / 1.1【1997年,最经典、使用最广泛】
主要解决了上一个版本痛点【TCP可以变为持久连接】,还多了一些PUT等请求方法。
-
HTTP / 2.0 【2015年,正在广泛使用起来,并不是取代HTTP / 1.1 】
HTTP/2 为 HTTP 语义提供了优化的传输。HTTP/2 支持 HTTP 的所有核心功能,但旨在比 HTTP/1.1 更高效。可以说改善了 HTTP / 1.1 版本的许多诟病。
-
HTTP / 3.0 【2018年, 还有很长的路要走】
HTTP/3是第三个主要版本的HTTP协议。与其前任HTTP/1.1和HTTP/2不同,在HTTP/3中,将弃用TCP协议,改为使用基于UDP协议的QUIC协议实现。
下面是,HTTP / 3.0 中对 1.1 版本 和 2.0 版本 的描述。
HTTP/1.1 uses whitespace-delimited text fields to convey HTTP messages. While these exchanges are human readable, using whitespace for message formatting leads to parsing complexity and excessive tolerance of variant behavior.
Because HTTP/1.1 does not include a multiplexing layer, multiple TCP connections are often used to service requests in parallel. However, that has a negative impact on congestion control and network efficiency, since TCP does not share congestion control across multiple connections.
HTTP/2 introduced a binary framing and multiplexing layer to improve latency without modifying the transport layer. However, because the parallel nature of HTTP/2's multiplexing is not visible to TCP's loss recovery mechanisms, a lost or reordered packet causes all active transactions to experience a stall regardless of whether that transaction was directly impacted by the lost packet.
-
二、HTTP的消息格式
// HTTP的消息格式 【请求报文 / 响应报文都满足这个格式】
HTTP-message = start-line CRLF // start-line = request-line / status-line
*( field-line CRLF )
CRLF
[ message-body ] // message-body = *OCTET
再来一段抓包抓到的HTTP报文【注:每一个空格、回车换行、符号,都是按上面的消息格式来的。先浅看一下,之后在解释】
GET /RapidSSLTLSDVRSAMixedSHA2562020CA-1.crl HTTP/1.1
Cache-Control: max-age = 10800
Connection: Keep-Alive
Accept: */*
If-Modified-Since: Tue, 05 Jul 2022 08:15:24 GMT
If-None-Match: "62c3f31c-6d945"
User-Agent: Microsoft-CryptoAPI/10.0
Host: crl4.digicert.com
HTTP/1.1 304 Not Modified
Accept-Ranges: bytes
Age: 4342
Cache-Control: max-age=10800, public
Date: Wed, 06 Jul 2022 03:33:21 GMT
Etag: "62c3f31c-6d945"
Expires: Wed, 06 Jul 2022 06:33:21 GMT
Last-Modified: Tue, 05 Jul 2022 08:15:24 GMT
Server: ECS (hhp/9AC8)
X-Cache: HIT
浅画一张图,解释一下对应的部分。
上面就是HTTP的消息格式。在解读他之前,我们先来了解一下定义这些报文的 规范语言 ABNF。
ABNF
- 简介
可以简单的理解成,ABNF是用来定义互联网技术规范中格式的一种语言。互联网技术规范通常需要定义正式的语法。BNF(巴科斯-瑙尔范式)的修改版本,称为 Augmented BNF (ABNF),在许多互联网规范中很流行 。当前的规范文档是ABNF。它平衡了紧凑性和简单性与合理的表示能力。标准BNF和ABNF之间的区别涉及命名规则、重复、替代、顺序-独立性和值范围。
-
几个核心语法
规则 含义 CRLF 互联网标准换行 a*b [a,b]个对应内容 【a:a个或多个】【 :0个或多个 】 ( ) 括起来的是一个整体 [ ] 括起来的是可有可无的 / 选其中一个 HTAB 横向制表符【Tab键】 SP 空格 DIGIT 数字(0~9) OWS *( SP / HTAB) OCTET 八位数据
消息格式解读
(1)综述
了解完ABNF的核心语法,再看看我们的消息格式。
HTTP-message = start-line CRLF
*( field-line CRLF )
CRLF
[ message-body ]
画了一张图,圈出了以下几个关键点。
- 消息的格式确定,要么是请求消息、要么是响应消息。
- 请求报文 / 响应报文 类型仅仅由 开始行来标识。
- 头部字段是一系列的八位数据组成。可以有 零个或多个。并且结尾由一个 空行 结束头部字段的描述。
- 消息体是可选的【可有可无】。
(2)开始行【start-line】
start-line = request-line / status-line
若是请求消息,那么开头就是请求行【request-line】,否则是响应消息,开头是状态行(响应行)【status-line】。
- 请求行【request-line】
请求行:开始是一个请求方法,紧接着一个空格、再是请求目标、然后另一个空格、结束于 HTTP协议的版本
request-line = method SP request-target SP HTTP-version
// 方法签名 + SP + 请求目标 + SP + HTTP版本
我们来看一看这五个请求报文的开始行 【request-line】,是不是发现格式确实是规定好的。都满足上面说的格式。
请求方法
常用的几种请求方法
-
GET:常用于读取的操作,请求参数直接拼接在 URL的后面 【浏览器对URL是有长度限制的】
-
POST:常用于添加、修改、删除的操作,请求参数可以放到请求体中【没有大小限制】
-
HEAD:常用语获取文件大小,其他部分与GET请求一样【没有响应体】
请求目标
HTTP是通过 URI 来标识 所请求的资源,一般这个资源标识就是用 这里的请求目标【request-target】来标识的。
request-target = origin-form
/ absolute-form
/ authority-form
/ asterisk-form
一般情况还会配合头部字段中的 HOST【所请求服务器的域名、端口号】 来使用。比如我们要请求
http://www.baidu.com/?query=test222
会变成这样。
GET /?query=test222 HTTP/1.1
Host: www.baidu.com
HTTP版本
格式固定为: HTTP/数字.数字
HTTP-version = HTTP-name "/" DIGIT "." DIGIT
HTTP-name = %s"HTTP"
如下图:
(3)状态行(响应行)【status-line】
响应消息的第一行是状态行,由协议版本、空格 (SP)、状态代码和另一个空格组成,并以描述状态代码的可选文本短语结尾。
status-line = HTTP-version SP status-code SP [ reason-phrase ]
// HTTP版本 + 空格 + 状态码 + 空格 + [描述码的信息]
状态码
响应的状态码是一个三位数的整数代码,描述了请求的结果和响应的语义,包括请求是否成功以及包含了什么内容(如果有的话)。所有有效的状态代码都在 100 到 599 的范围内,包括 100 到 599。
| 状态码综述 | 描述 |
|---|---|
| 1xx【Informational】 | 请求将会被服务器接受,并且继续处理 |
| 2xx【Successful】 | 请求被服务器成功接受、解析、接受 |
| 3xx【Redirection】 | 还需要额外的行动来完成请求【重定向】 |
| 4xx【Client Error】 | 客户端的请求有误,服务器不能处理该请求 |
| 5xx【Server Error】 | 服务器有故障 |
有很多的状态码,官方也说了,没必要全部理解。可根据首位数字,大致推断所表达的意思即可。自己知道一些常见的状态码就行了。百度查一下,也有很多。
(4)头部字段
这一部分打算放在下一篇文章内。因为头部字段有很多能说的知识点。比如;跨域、Cookie和Session、缓存、文件上传的相关字段...
(5)消息体【message-body】
消息体也有两种,一是请求体,二是响应体。不论是哪一种,都是用于携带内容的。HTTP报文也可能没有消息体,譬如GET请求就没有请求体。
message-body = *OCTET
// 零个或多个八位数据【长度不限,也可以没有消息体】
几个例子:
- 没有消息体
- 请求体和响应体都有
- 只有请求体
- 只有响应体
写在最后
- 中文译文:如何阅读RFC? ,原文网站:How to Read an RFC
- 下周写下一篇【HTTP的头部字段】:跨域、Cookie和Session、缓存、文件上传的相关字段
- 不管文章写得怎么样,自己是得到锻炼了~