网络协议01-Http-工作原理补充
HTTP协议工作原理全面深度解析
HTTP协议的工作原理本质上是**“客户端发起请求-服务器处理请求-返回响应”**的标准化通信流程,但这个看似简单的流程背后包含了域名解析、传输层连接、报文交换、状态管理、缓存控制等多个复杂环节。不同版本的HTTP协议在连接管理、数据传输效率等方面有显著差异,但核心的请求-响应模型始终保持一致。
一、HTTP协议的核心基础模型
1.1 客户端-服务器(C/S)架构
HTTP采用严格的单向C/S架构:
- 客户端(Client):主动发起通信的一方,通常是浏览器、移动App、爬虫程序等
- 服务器(Server):被动等待请求的一方,运行在物理服务器或云服务器上,监听80(HTTP)或443(HTTPS)端口
- 中间节点:代理服务器、CDN、网关等,它们既可以作为客户端也可以作为服务器,转发请求和响应
这种架构的优势是职责清晰、易于扩展,服务器可以同时处理成千上万个客户端的请求。
1.2 请求-响应模型
所有HTTP通信都遵循严格的请求-响应模式:
- 通信只能由客户端主动发起
- 服务器只能被动响应客户端的请求
- 一个请求对应一个响应,响应必须跟在请求之后
- 没有请求就不会有响应
重要区别:这与WebSocket等全双工协议不同,WebSocket允许服务器主动向客户端推送数据。
1.3 无状态性与无连接性
- 无状态性:服务器不会在多个请求之间保存任何客户端的状态信息。每个请求都是完全独立的,服务器无法区分两个请求是否来自同一个客户端。
- 无连接性:早期HTTP/0.9/1.0每次请求都需要建立一个新的TCP连接,请求完成后立即关闭连接。HTTP/1.1及以后版本引入了持久连接,实现了"逻辑上无连接,物理上长连接"。
二、完整HTTP通信端到端总流程
当你在浏览器地址栏输入https://www.example.com/index.html并按下回车时,会触发以下10个核心步骤:
用户输入URL → DNS域名解析 → 建立TCP连接 → 建立TLS安全连接 → 客户端发送HTTP请求 → 服务器接收并处理请求 → 服务器返回HTTP响应 → 客户端解析响应 → 渲染页面并请求子资源 → 连接管理(关闭/复用)下面我们对每个环节进行深度拆解。
三、各环节工作原理深度详解
3.1 DNS域名解析:将域名转换为IP地址
计算机只能识别IP地址,无法直接识别域名,因此需要DNS(Domain Name System)系统将人类可读的域名转换为机器可读的IP地址。
3.1.1 域名结构
域名采用分层结构,从右到左依次为:
www.example.com. └── 根域(.) └── 顶级域(com) └── 二级域(example) └── 三级域(www)3.1.2 完整解析流程(按优先级)
- 浏览器缓存:浏览器首先检查自身缓存中是否有该域名对应的IP地址(Chrome可通过
chrome://net-internals/#dns查看) - 操作系统缓存:如果浏览器缓存没有命中,查询操作系统的DNS缓存(Windows:
ipconfig /displaydns, Linux:/etc/hosts文件) - 路由器缓存:查询本地路由器的DNS缓存
- ISP DNS服务器:查询互联网服务提供商(ISP)的DNS服务器缓存
- 递归查询:如果以上都没有命中,ISP DNS服务器会向根DNS服务器发起递归查询
- 迭代查询:
- 根DNS服务器返回顶级域(com)服务器的IP地址
- ISP DNS向顶级域服务器查询,返回二级域(example)服务器的IP地址
- ISP DNS向权威DNS服务器查询,最终得到www.example.com的IP地址
- 返回结果:ISP DNS将IP地址返回给客户端,并缓存结果以备后续使用
3.1.3 递归查询 vs 迭代查询
- 递归查询:客户端只需要发起一次请求,DNS服务器会替客户端完成所有查询工作,最终返回结果
- 迭代查询:DNS服务器只返回下一个应该查询的服务器地址,客户端需要自己发起后续请求
实际情况:客户端到ISP DNS是递归查询,ISP DNS到根、顶级、权威DNS是迭代查询。
3.2 传输层连接建立
HTTP是应用层协议,它依赖传输层的TCP协议来保证数据的可靠传输。HTTPS还需要在TCP之上建立TLS安全连接。
3.2.1 TCP三次握手详解
TCP通过三次握手建立可靠连接,目的是确认双方的发送和接收能力都正常,并同步初始序列号(ISN)。
客户端 服务器 | | | SYN=1, seq=x | 第一次握手:客户端发送SYN包,请求建立连接 |------------------------------------>| | | | SYN=1, ACK=1, seq=y, ack=x+1 | 第二次握手:服务器发送SYN+ACK包,确认连接请求 |<------------------------------------| | | | ACK=1, seq=x+1, ack=y+1 | 第三次握手:客户端发送ACK包,连接建立完成 |------------------------------------>| | |- SYN:同步标志位,用于建立连接
- ACK:确认标志位,用于确认收到数据
- seq:序列号,标识发送的数据字节流
- ack:确认号,表示期望收到的下一个字节的序列号
为什么是三次握手而不是两次?
- 防止已失效的连接请求报文段突然又传送到服务器,导致服务器错误地建立连接
- 确保双方都知道对方的接收能力正常
- 同步双方的初始序列号
3.2.2 HTTPS的TLS握手过程
HTTPS在TCP连接建立后,还需要进行TLS握手来建立安全通道。TLS 1.3相比TLS 1.2大幅简化了握手过程,减少了RTT(Round-Trip Time)。
TLS 1.2完整握手(4次RTT):
- 客户端发送ClientHello:支持的TLS版本、加密套件、随机数Client Random
- 服务器返回ServerHello:选择的TLS版本、加密套件、随机数Server Random
- 服务器发送证书:包含服务器公钥的数字证书
- 服务器发送ServerHelloDone:表示服务器端握手消息发送完毕
- 客户端发送ClientKeyExchange:使用服务器公钥加密的预主密钥(Pre-Master Secret)
- 客户端发送ChangeCipherSpec:表示后续数据将使用协商好的密钥加密
- 客户端发送Finished:加密的握手消息摘要,用于验证握手过程
- 服务器发送ChangeCipherSpec
- 服务器发送Finished
- 握手完成,开始传输加密的HTTP数据
TLS 1.3简化握手(1-RTT):
TLS 1.3合并了多个握手步骤,将握手时间从2-RTT减少到1-RTT,还支持0-RTT握手(在有过连接记录的情况下)。
3.3 客户端发送HTTP请求
连接建立后,客户端会构建并发送HTTP请求报文。
3.3.1 请求报文的构建过程
- 确定请求方法:根据操作类型选择GET、POST、PUT等
- 构建请求URI:协议+域名+端口+路径+查询参数
- 添加请求头:自动添加Host、User-Agent、Accept、Cookie等头部
- 准备请求体:如果是POST/PUT等方法,将数据编码为指定格式(JSON、FormData等)
- 添加空行:分隔请求头和请求体
- 发送报文:通过TCP套接字将完整的请求报文发送给服务器
3.3.2 常见请求体编码格式
- application/x-www-form-urlencoded:默认格式,数据被编码为键值对,用
&分隔,如username=admin&password=123456 - multipart/form-data:用于上传文件,数据被分割为多个部分
- application/json:现代API最常用的格式,数据以JSON字符串形式传输
- text/plain:纯文本格式
3.4 服务器端请求处理流程
服务器端的处理流程通常由Web服务器(如Nginx、Apache)和应用服务器(如Tomcat、Node.js)共同完成。
- 监听端口:Web服务器监听80或443端口,等待客户端连接
- 接收数据:从TCP套接字接收字节流,重组为完整的HTTP请求报文
- 解析请求:
- 解析请求行:获取请求方法、URI、协议版本
- 解析请求头:提取Host、Content-Type、Cookie等信息
- 解析请求体:根据Content-Type解码请求体数据
- 路由匹配:根据请求方法和URI,将请求映射到对应的处理函数
- 业务逻辑处理:
- 静态资源请求:直接读取文件系统中的文件
- 动态请求:调用应用程序代码,可能涉及数据库查询、计算等操作
- 生成响应:
- 设置状态码和状态描述
- 添加响应头:Content-Type、Content-Length、Set-Cookie等
- 准备响应体:HTML、JSON、图片等数据
- 发送响应:将响应报文通过TCP套接字发送给客户端
- 日志记录:记录请求的访问日志,包括时间、IP、URI、状态码、响应时间等
3.5 客户端响应处理流程
客户端接收到响应报文后,会进行一系列处理,最终将结果展示给用户。
- 接收数据:从TCP套接字接收字节流,重组为完整的HTTP响应报文
- 解析响应:
- 解析状态行:获取协议版本、状态码、状态描述
- 解析响应头:提取Content-Type、Content-Length、Cache-Control等信息
- 解析响应体:根据Content-Type解码响应体数据
- 处理状态码:
- 2xx:成功,继续处理响应体
- 3xx:重定向,根据Location头发起新的请求
- 4xx:客户端错误,显示错误页面
- 5xx:服务器错误,显示错误页面
- 处理响应头:
- 缓存处理:根据Cache-Control等头部决定是否缓存响应
- Cookie处理:根据Set-Cookie头保存或更新Cookie
- 编码处理:根据Content-Encoding头解压响应体
- 解析响应体:
- 如果是HTML:解析为DOM树
- 如果是CSS:解析为CSSOM树
- 如果是JavaScript:执行JavaScript代码
- 如果是图片/视频:解码并显示
- 页面渲染:
- 合并DOM树和CSSOM树,生成渲染树(Render Tree)
- 布局(Layout):计算每个元素的位置和大小
- 绘制(Paint):将元素绘制到屏幕上
- 合成(Composite):将多个层合并为最终的屏幕图像
- 发起子资源请求:解析HTML时,遇到
<link>、<script>、<img>等标签,会发起新的HTTP请求获取这些资源
四、HTTP连接管理机制演进
连接管理是HTTP协议性能优化的核心,不同版本的HTTP在连接管理上有巨大差异。
4.1 HTTP/0.9/1.0:短连接
- 工作原理:每次HTTP请求都需要建立一个新的TCP连接,请求完成后立即关闭连接
- 缺点:
- 连接建立和关闭的开销大(三次握手和四次挥手)
- TCP慢启动机制导致数据传输效率低
- 并发请求需要建立多个TCP连接,消耗服务器资源
4.2 HTTP/1.1:持久连接与管道化
4.2.1 持久连接(Keep-Alive)
- 工作原理:默认启用
Connection: keep-alive,一个TCP连接可以处理多个HTTP请求 - 优势:
- 减少了连接建立和关闭的开销
- 避免了TCP慢启动的影响
- 提高了数据传输效率
- 限制:
- 同一时间一个TCP连接只能处理一个请求
- 存在队头阻塞问题:如果前面的请求处理缓慢,后面的请求会被阻塞
4.2.2 管道化(Pipelining)
- 工作原理:允许客户端在一个TCP连接上同时发送多个请求,而不需要等待前一个请求的响应
- 失败原因:
- 服务器必须按照请求的顺序返回响应,队头阻塞问题依然存在
- 很多代理服务器不支持管道化
- 实现复杂,容易出现兼容性问题
- 结果:几乎没有浏览器默认启用管道化
4.3 HTTP/2:多路复用
HTTP/2的核心改进是引入了二进制分帧层,彻底解决了HTTP/1.1的队头阻塞问题。
4.3.1 二进制分帧层
HTTP/2将所有传输的数据分割为更小的帧(Frame),并采用二进制格式编码,而不是HTTP/1.x的纯文本格式。
4.3.2 核心概念
- 帧(Frame):HTTP/2数据传输的最小单位,每个帧包含帧头和帧体,帧头标识该帧所属的流
- 消息(Message):对应HTTP/1.x的一个请求或响应,由一个或多个帧组成
- 流(Stream):连接中的一个双向字节流,可以承载一个或多个消息
4.3.3 多路复用工作原理
- 一个TCP连接上可以同时存在多个并发的流
- 不同流的帧可以交错发送,不需要按顺序
- 接收方根据帧头中的流标识符将帧重新组装成完整的消息
- 彻底解决了队头阻塞问题:一个流的阻塞不会影响其他流
4.3.4 其他HTTP/2特性
- 头部压缩(HPACK):使用静态字典和哈夫曼编码压缩请求头和响应头,减少了头部开销
- 流优先级:客户端可以为每个流设置优先级,服务器优先处理高优先级的请求
- 服务器推送(Server Push):服务器可以主动向客户端推送客户端可能需要的资源,而不需要等待客户端发起请求
4.4 HTTP/3:基于QUIC的无队头阻塞传输
HTTP/2虽然解决了应用层的队头阻塞问题,但TCP层的队头阻塞问题依然存在:如果一个TCP数据包丢失,整个连接上的所有数据都必须等待重传。
HTTP/3将底层传输协议从TCP改为QUIC(Quick UDP Internet Connections),彻底解决了队头阻塞问题。
4.4.1 QUIC协议核心特性
- 基于UDP:UDP是无连接的,不需要建立和关闭连接的开销
- 0-RTT/1-RTT连接建立:首次连接需要1-RTT,后续连接可以实现0-RTT
- 连接迁移:当客户端的IP地址或端口发生变化时(如从Wi-Fi切换到4G),连接可以保持不中断
- 流级别的拥塞控制:每个流独立进行拥塞控制,一个流的数据包丢失不会影响其他流
- 内置TLS 1.3:安全和传输层合并,减少了握手时间
4.4.2 HTTP/3工作原理
HTTP/3保留了HTTP/2的语义(请求方法、状态码、头部等),但将传输层从TCP改为QUIC。HTTP/3的帧格式和头部压缩(QPACK)也与HTTP/2略有不同。
五、HTTP状态保持机制
HTTP是无状态协议,但实际应用中需要跟踪用户的状态(如登录状态、购物车等)。HTTP通过以下几种机制实现状态保持。
5.1 Cookie
工作原理:
- 服务器通过
Set-Cookie响应头向客户端发送Cookie - 客户端将Cookie保存在本地
- 后续请求中,客户端自动将Cookie通过
Cookie请求头发送给服务器 - 服务器根据Cookie识别用户身份
- 服务器通过
Cookie核心属性:
Domain:指定Cookie所属的域名Path:指定Cookie所属的路径Expires/Max-Age:指定Cookie的过期时间HttpOnly:防止JavaScript读取Cookie,防范XSS攻击Secure:只在HTTPS连接中发送CookieSameSite:防止CSRF攻击,可选值Strict、Lax、None
5.2 Session
工作原理:
- 服务器为每个用户创建一个唯一的Session ID
- 将Session ID通过Cookie发送给客户端
- 服务器端存储Session ID对应的用户状态信息
- 后续请求中,客户端发送Session ID,服务器根据Session ID获取用户状态
Session存储方式:
- 内存:开发环境常用,重启服务器会丢失
- 数据库:生产环境常用,持久化存储
- Redis:高性能分布式存储,适合集群环境
5.3 Token认证机制
JWT(JSON Web Token):最常用的Token格式,由三部分组成:
- Header:指定算法和令牌类型
- Payload:包含用户信息和过期时间等声明
- Signature:使用服务器私钥对Header和Payload进行签名,防止篡改
工作流程:
- 用户登录,服务器验证身份后生成JWT
- 服务器将JWT返回给客户端
- 客户端将JWT保存在本地(通常是LocalStorage)
- 后续请求中,客户端将JWT放在
Authorization请求头中发送给服务器 - 服务器验证JWT的签名和有效性,获取用户信息
六、HTTP缓存机制
缓存是HTTP协议中最重要的性能优化手段之一,它可以减少网络传输,提高页面加载速度。
6.1 缓存分类
- 浏览器缓存:存储在客户端本地
- 代理缓存:存储在代理服务器上
- CDN缓存:存储在CDN节点上
6.2 强缓存(本地缓存)
强缓存不需要向服务器发送请求,直接从本地缓存中读取资源。
控制头部:
Cache-Control: max-age=3600:资源在3600秒内有效Cache-Control: no-cache:不使用强缓存,必须向服务器验证Cache-Control: no-store:不缓存任何内容Expires: Thu, 21 May 2026 08:34:56 GMT:HTTP/1.0遗留头部,指定资源的过期时间
命中条件:当前时间小于资源的过期时间
6.3 协商缓存(验证缓存)
当强缓存失效时,客户端会向服务器发送请求,验证资源是否更新。如果资源没有更新,服务器返回304状态码,客户端继续使用本地缓存;如果资源已更新,服务器返回200状态码和新的资源。
验证头部:
Last-Modified/If-Modified-Since:基于资源的最后修改时间ETag/If-None-Match:基于资源的唯一标识符(通常是文件内容的哈希值)
工作流程:
- 客户端第一次请求资源,服务器返回200状态码和资源,同时返回
Last-Modified和ETag头 - 客户端缓存资源和这两个头部
- 第二次请求资源时,客户端发送
If-Modified-Since和If-None-Match头 - 服务器比较这两个值与资源的当前值
- 如果资源未修改,返回304 Not Modified,客户端使用本地缓存
- 如果资源已修改,返回200 OK和新的资源
- 客户端第一次请求资源,服务器返回200状态码和资源,同时返回
6.4 ETag vs Last-Modified
- ETag精度更高:可以精确到字节级别的变化
- ETag可以解决Last-Modified的问题:
- 资源周期性修改但内容不变
- 资源修改非常频繁(小于1秒)
- 服务器无法准确获取资源的最后修改时间
七、完整端到端示例:访问https://www.baidu.com
为了更好地理解HTTP的工作原理,我们以访问百度首页为例,完整走一遍整个流程:
- 用户输入URL:在浏览器地址栏输入
https://www.baidu.com并按下回车 - DNS解析:
- 浏览器缓存没有命中
- 操作系统缓存没有命中
- 路由器缓存没有命中
- ISP DNS缓存命中,返回百度服务器的IP地址
180.101.50.242
- 建立TCP连接:与
180.101.50.242:443进行三次握手 - 建立TLS连接:进行TLS 1.3握手,1-RTT完成
- 发送HTTP请求:
GET / HTTP/2 Host: www.baidu.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7 Cookie: BAIDUID=ABC123DEF456; BIDUPSID=789GHI012JKL; PSTM=1716276896 - 服务器处理请求:
- 百度的Nginx服务器接收请求
- 路由匹配到首页处理程序
- 生成HTML响应
- 返回HTTP响应:
HTTP/2 200 OK Date: Thu, 21 May 2026 08:35:00 GMT Server: BWS/1.1 Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Cache-Control: private Set-Cookie: BD_UPN=12314753; expires=Thu, 21-May-2026 08:35:00 GMT; path=/; domain=.baidu.com - 客户端解析响应:
- 解压gzip编码的HTML
- 解析HTML生成DOM树
- 发起子资源请求:
- 解析到
<link rel="stylesheet" href="/css/index.css">,发起GET请求获取CSS - 解析到
<script src="/js/index.js">,发起GET请求获取JS - 解析到
<img src="/logo.png">,发起GET请求获取图片
- 解析到
- 页面渲染:
- 合并DOM树和CSSOM树生成渲染树
- 布局、绘制、合成,最终显示百度首页
- 连接保持:TCP连接保持打开状态,用于后续请求
