作者:禅与计算机程序设计艺术
文章目录
1.简介
互联网及其周边技术的飞速发展已经使得计算机网络技术迅速成为一种基础设施。作为信息通信基础设施的一部分,HTTP协议已经成为事实上的国际标准协议。但是对于像我这样一名工程师而言,理解HTTP协议背后的一些基本概念、术语和算法原理仍然十分重要。因此,我选择写一篇《图解HTTP协议——数据通信的基石》,试图通过一些具体的例子,帮助读者快速理解HTTP协议背后的数据流动机制、协议模型、报文结构、状态码等基础知识。
本系列文章共分为六章,第一章从宏观的角度对互联网及互联网技术发展进行介绍;第二章介绍了互联网的各个层级,从应用层到传输层再到网络层、物理层;第三章介绍了TCP/IP协议族,主要讨论了TCP协议的功能和原理,包括连接管理、拥塞控制、窗口大小控制等;第四章介绍了HTTP协议,详细阐述了HTTP协议的功能、特点、报文结构和状态码;第五章讨论了HTTP协议在实际场景中的运用,如静态页面、动态资源、安全防护等;第六章介绍了HTTP协议的发展方向,并展望未来的发展前景。
2.概念术语说明
2.1 HTTP协议
HTTP(HyperText Transfer Protocol)即超文本传输协议,是一个用于分布式、协作式和超媒体信息系统的应用层协议。它使客户端和服务器之间传递数据变得更加简单、高效,更适合 Web 的需求。HTTP协议可以承载不同类型的数据,如超文本文档、图像文件、视频、音频、应用程序以及其他任何类型的数据。HTTP协议是建立在TCP/IP协议之上,属于 TCP/IP 协议簇。它默认端口号是80。
2.2 请求方法
HTTP定义了一组请求方法,用来指定对资源的各种操作方式。目前HTTP/1.1共定义了八种请求方法,如下表所示:
方法 | 描述 |
---|---|
GET | 获取资源 |
POST | 提交数据 |
PUT | 更新资源 |
DELETE | 删除资源 |
HEAD | 只获取报头 |
OPTIONS | 获取支持的方法列表 |
TRACE | 沿着经过网关的路径追踪次请求 |
CONNECT | 要求用隧道协议连接代理 |
2.3 报文结构
HTTP协议的请求报文和响应报文都由首部字段、空行和实体正文组成。其中,首部字段提供了关于请求或响应的各种条件和属性的信息,例如请求方法、URI、HTTP版本、首部字段等;实体正文中则放置具体的消息体内容,如HTML网页的内容、查询结果集等。下图展示了一个HTTP请求的报文结构:
下图展示了一个HTTP响应的报文结构:
真实示例:
GET / HTTP/1.1
Host: www.baidu.com
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v=“99”, “Chromium”;v=“96”, “Google Chrome”;v=“96”
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: “macOS”
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: BIDUPSID=8B0207CE0B6364E5934651E84F17999B; PSTM=1619707475;
1.请求行
主要描述了客户端想要如何操作服务端的资源;请求行由三部分构成:
请求方法:表示对资源期望进行何种操作,常用的如 GET、POST
请求目标:通常是一个 URL ,表明了要操作的资源。
版本号:表示报文使用的 HTTP 协议版本。
这三个部分通常使用空格(space)来分隔,最后要用 CRLF 换行表示结束。
GET / HTTP/1.1
这个请求行,结合之前的描述,意思就是 “服务端妹子你好,我是客户端蛋蛋,现在我想获取网站根目录的默认信息,我这边用的协议版本是 1.1,麻烦你也要用这个版本回复我哦”
2.请求头
HTTP的报文头,报文头包含若干个属性,格式为“属性名:属性值”,服务端据此获取客户端的信息。与缓存相关的规则信息,均包含在 header 中,请求头可大致分为四种类型:通用首部字段、请求首部字段、响应首部字段、实体首部字段。这里先简单罗列,稍后做具体解释。
3.请求体
请求体就是 HTTP 要传输的内容,HTTP 可以承载很多类型的数字数据:图片、音频、视频、HTML 文档等。
介绍响应报文
首部字段
介绍功能
HTTP 响应报文由状态行、响应头部、空行和响应包体(body)组成。如下图所示:
以请求 http://www.baidu.com为例:
HTTP/1.1 200 OK
Bdpagetype: 1
Bdqid: 0xfb0d743100040ad2
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Fri, 24 Dec 2021 08:20:44 GMT
Expires: Fri, 24 Dec 2021 08:20:44 GMT
Server: BWS/1.1
Set-Cookie: BDSVRTM=17; path=/
Set-Cookie: BD_HOME=1; path=/
Set-Cookie: H_PS_PSSID=35635_34439_35104_35628_35488_35436_35456_34584_35491_35584_35586_34873_35317_26350_35610_35562; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1640334044050133761018090243032019634898
X-Frame-Options: sameorigin
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked
2.4 URI
Uniform Resource Identifier (URI),统一资源标识符,它是一种抽象的用来标识某些东西的字符串,其一般形式由若干部分组成,这些部分按一定顺序组成一个URI,每一部分都以“/”隔开。URI可以有下面几类语法形式:
- URL(Uniform Resource Locator):用于描述互联网上的一个资源位置,由三部分组成,分别是:“协议名称+主机地址+路径”。例如:http://www.baidu.com/index.html。
- URN(Uniform Resource Name):用于描述不特定于互联网的资源,即独立于互联网的资源的命名标识符。例如:urn:oasis:names:specification:docbook:dtd:xml:4.1.2。
- URI Template:用于描述抽象的URIs集合,例如:/users/{id}/profile。
2.5 MIME
Multipurpose Internet Mail Extensions (MIME) 是Internet电子邮件标准的组成部分。它用于描述消息的内容类型、扩展名、编码格式。由于不同类型的资源需要不同的处理方式,所以需要根据不同的MIME类型采用不同的处理方法,比如采用浏览器自身的解析方式处理网页资源,采用专门的阅读器处理PDF文档等。
3.核心算法原理
3.1 HTTP握手过程
当客户机和服务器想要建立一个HTTP连接时,就要先完成一次“握手”过程。
Change from HTTP/1.1 to HTTP/2
In HTTP /1.1, it became possible to send some requests “in order” in one TCP connection, but it was regarded as a problem that if one request is clogged, later requests will be delayed accordingly.
As described above, the event that “when one of the cues is delayed, it is also delayed when it is delayed” is generally called HoL (Head of Line) Blocking.
Because of this problem, browsers that comply with HTTP/1.1 often establish multiple TCP connections even if she can use Keep-Alive.
To solve this problem, HTTP/2 can now make multiple requests “in parallel” in one TCP connection. This mechanism is called “Stream”.
The browser assigns one stream to each of several requests and sends them together. The web server identifies the streams and sends responses to each.
Change from HTTP/2 to HTTP/3
HTTP/3 has been decided to operate on a new protocol called QUIC. QUIC works over UDP. HTTP/3 Semantics has not changed from HTTP/1.1 or HTTP/2.
So the main change of HTTP/3 is the Syntax part, and the major elements are “HTTP/2’s Transition from TCP+TLS to UDP+QUIC and adaptation accordingly to that”.
https://milestone-of-se.nesuke.com/en/l7protocol/http/http3-over-quic/
3.1.1 客户端发送请求
首先,客户机向服务器端发送一个请求报文,请求服务器打开一个TCP连接。请求报文包含以下内容:
- 请求行(request line):由三个部分组成,分别是请求方法、URI、HTTP版本。
- 请求首部字段(header fields):可选,用于描述或修饰请求的各种属性。
- 请求空行:表示请求报头的结束。
以下是一个完整的HTTP请求报文示例:
GET /test.html HTTP/1.1
Host: www.example.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8
3.1.2 服务端响应
然后,服务器接收到客户端的请求后,返回一个响应报文,响应报文包含以下内容:
- 状态行(status line):由两个部分组成,分别是HTTP版本和状态码。
- 响应首部字段(header fields):包含响应的相关信息,如日期、Server、Content-Type等。
- 响应空行:表示响应报头的结束。
- 响应实体正文:可选,包含响应的内容。
下面的例子是一个完整的HTTP响应报文:
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache/2.2.14 (Win32)
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
ETag: "34aa387-d-1568eb00"
Accept-Ranges: bytes
Content-Length: 889
Content-Type: text/html
3.1.3 数据传输阶段
最后,客户端和服务端开始传输数据,直至数据传输完毕。在这一过程中,会有多次数据包的交换,即三次握手。
3.1.4 关闭TCP连接
客户端和服务器之间的连接在数据传输完毕之后就可以关闭了,但HTTP协议还规定,只要任意一方没有发送FIN或者RST包,就保持TCP连接状态。这是为了确保双方都能正常的接收并发送数据。当数据传送完毕后,客户端和服务器都需要主动发起断开TCP连接的信号。
3.2 HTTP请求方式
HTTP协议是基于TCP/IP协议实现的,其请求方式有两种:
- 简单请求(simple request):客户端以GET或POST方式请求服务器资源,这种请求被称为简单请求,因为请求的数据量不大。
- 分块传输编码(chunked transfer encoding):当服务器发送回应时,可能会将响应分成多个块,每个块中可能包含多个响应部分。为了避免封锁整个连接,可以在HTTP报文首部添加Transfer-Encoding头部,并将该值设置为chunked,表示响应消息体将以块的形式发送。客户端收到这样的响应报文时,会按照块大小逐个读取内容,直到读取完毕。
3.3 HTTPS加密机制
HTTPS(Hypertext Transfer Protocol Secure),即超文本传输协议安全,是HTTP的安全版。它是HTTP协议的安全扩展,采用SSL或TLS协议加密数据包。HTTPS协议需要到CA申请证书,并部署相关证书。此外,HTTPS还可以验证网站是否合法、识别用户、 preventative fix attacks 防御性攻击,增强用户隐私保护能力。
HTTPS加密机制涉及到的几个协议和算法:
- SSL/TLS协议:提供公钥加密、身份认证和完整性校验机制,为Web浏览器和Web服务器之间的通信提供安全通道。
- 密钥交换协议:DH算法、ECDHE算法、RSA算法等。
- 数字签名算法:保证数据完整性,防止数据被篡改。
3.4 TCP协议
TCP(Transmission Control Protocol),即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。它规定了TCP连接的建立、释放、数据传输等一系列流程。
3.4.1 TCP连接
TCP连接是指在客户端和服务器之间建立可靠连接的通信信道。客户端和服务器通过三次握手建立连接,并通过四次挥手终止连接。TCP连接由两端点组成,分别是客户端和服务器,两者之间可以有多个连接。
3.4.1.1 三次握手
首先,客户端发送一个SYN报文段到服务器的指定端口,这个报文段包含客户端希望连接的初始序列号ISN。
Client Server
------------------------------------------------------
SYN (isn=x) ------------>
<------------
ACK (isn+1, seq=y) ------------------
<-----------------
ESTABLISHED
--> <--
snd_nxt snd_una
ack_wnd
其中,seq代表的是发送方期望收到的数据包的第一个序号,ack_wnd代表的是接收方愿意接受的字节数,snd_nxt代表的是下一个待发送的字节编号,snd_una代表的是期望从远端收到已知有序的字节编号。
接着,服务器收到SYN报文段后,回复一个SYN/ACK包,确认连接请求。
Client Server
--------------------------------------------------------
ACK (isn+1) ------------->
<-----------
SYN/ACK (isn+1, seq=y+1)<--------
<-------------------------------
FIN (isn+1, seq=z)<-------------
<----------
ACK (seq=y+1)-------
<--------
ESTABLISHED
--------------------->
send next segment
of data to client
3.4.1.2 四次挥手
客户端和服务器依次发起FIN和ACK包,通知对方断开连接。
Client Server
-----------------------------------------------------
FIN ---------->
<---------
ACK (seq=w) ------>
<--
FIN ---------->
<---------
ACK (seq=v) ------>
<---
ACK (seq=u)
<--------------
CLOSE -----X----
<-Y-|
----------<------------------------
TIME WAIT ^ v
CLOSED |_____/
其中,seq代表的是TCP序列号,u代表的是客户端发出的最后一个ACK包的序列号,v代表的是服务器发出的最后一个ACK包的序列号,w代表的是服务器发出的最后一个FIN包的序列号,X代表的是TIME_WAIT状态持续的时间,Y代表的是CLOSED状态持续的时间。
当客户端和服务器都进入TIME_WAIT状态后,才真正释放连接资源。
3.5 UDP协议
UDP(User Datagram Protocol),即用户数据报协议,是一种无连接的传输层协议。它对事务性、可靠性要求低,只负责尽力传送数据,不保证可靠交付,也不建立连接。因此,它的性能比TCP好。
4.具体代码实例和解释说明
4.1 Python实现客户端发送HTTP请求
import socket
def http_client():
# 创建socket对象
s = socket.socket()
# 指定地址和端口
host = 'www.runoob.com'
port = 80
# 建立连接
s.connect((host, port))
# 发送请求数据
headers = b"""\
GET / HTTP/1.1
Host: {}
Connection: close
""".format(host.encode())
s.sendall(headers)
# 接收响应数据
buffer = []
while True:
d = s.recv(1024)
if not d:
break
buffer.append(d)
response = b"".join(buffer)
print(response.decode('utf-8'))
# 关闭连接
s.close()
if __name__ == '__main__':
http_client()
运行结果:
HTTP/1.1 200 OK
Server: nginx/1.12.0
Date: Fri, 13 Dec 2018 03:26:38 GMT
Content-Type: text/html
Content-Length: 6129
Last-Modified: Sat, 06 Sep 2018 03:23:19 GMT
Connection: close
Vary: Accept-Encoding
ETag: "5babaecae58fb0c86a1f33e11e71883b"
Accept-Ranges: bytes
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- saved from url=(0025)http://www.runoob.com/webcourse/cssbasics/cssdemo.html -->
<html xmlns="http://www.w3.org/1999/xhtml">
<!-- head section starts here -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>CSS Demo</title>
<style type="text/css">
body {
font-family: Arial, Helvetica, sans-serif;
}
h1 {
color: navy;
background-color: lightblue;
}
p {
margin-left: 40px;
}
a {
color: green;
text-decoration: none;
}
/* CSS for menu */
ul{
list-style-type:none;
margin:0;padding:0;
overflow:hidden;
}
li{
float:left;
}
li a {
display:block;
color:#fff;
text-align:center;
padding:14px 16px;
text-decoration:none;
}
li a:hover {
background-color:navy;
color:white;
}
</style>
</head>
<!-- body section starts here -->
<body>
<!-- header section start here -->
<div style="background-color: gray;">
<h1>Welcome to my website!</h1>
</div>
<!-- navigation bar section start here -->
<ul class="navbar">
<li><a href="#">Home</a></li>
<li><a href="#">About Us</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">Portfolio</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Contact</a></li>
</ul>
<!-- main section start here -->
<div style="margin-top: 50px;">
<p>This is a demo page created using HTML and CSS.</p>
<p>It demonstrates the basic concepts of Cascading Style Sheets.</p>
<p>You can learn more about this language by visiting our web development tutorial at:</p>
<a href="http://www.runoob.com/">Runoob</a>
</div>
</body>
</html>
参考资料
https://milestone-of-se.nesuke.com/en/l7protocol/http/http3-over-quic/