精读《图解HTTP》:互联网软件工程师应当具备的网络基础知识

198 阅读18分钟

善人者,不善人之师;不善人者,善人之资 —— 《道德经》

这篇文章是我对上野宣所著《图解HTTP》一书的笔记,旨在结合自身多年的大前端开发经验,从理论上重新对HTTP协议知识进行梳理和盘点。本文主要回答以下五个问题:

  1. HTTP协议是什么,它在怎样的背景下出现
  2. 为什么会需要HTTP协议,它主要解决什么问题
  3. 针对要解决的问题,它采用怎样的设计思路就,其中有哪些精妙之处
  4. 未来的发展方向是怎样的

HTTP协议是什么

所谓“协议(Protocol)”,通俗意义上,是指经过多方谈判、协商后制定的共同承认、遵守的文件,这种文件通常是多方经协商后打成的共识,具有法律效力,用于保障各方的合法权益。在网络通信领域,协议有其特殊含义,指的是数据交换过程中必须遵守的规则和格式,是计算机网络通信的基础。

HTTP是HyperText Transfer Protocol 的缩写,通常被翻译为“超文本传输协议”——这种译法并不严谨,严谨的译法应当是“超文本转移协议”。它是一种用于分布式、协作式和超媒体信息系统的应用层协议。

出于跨越空间进行知识共享的设想,WWW万维网的概念诞生于1989年3月,它包含三个方面的内容,分别是HTML、HTTP和URL。

  • HTML:HyperText Markup Language,超文本传输语言,定义了页面的表现形式
  • HTTP:HpyerText Transfer Protocol,超文本传输协议,定义了数据传输的协议
  • URL:Uniform Resource Locator,统一资源定位符,定义了文档所在的地址

可以用“送信”来形容WWW技术,首先必须明确信件的内容格式(HTML),例如必须要有收件人地址和发件人信息,内容上使用“称呼-问候语-正文-结尾”的结构;其次,采用双方都认可的方式来传输信件(HTTP),例如乙要求信件必须贴5张邮票、使用牛皮纸信封;当写好信以后,要明确信件将投递给哪个地址(URL)。

以上便是HTTP协议的基本定义和出现的背景。

为什么需要HTTP协议

要理解HTTP的作用,首先应当介绍TCP/IP协议族的概念。互联网上的两台设备(这里使用“设备”,是因为通信对象不仅仅是计算机,还包括交换机、路由器等等各种硬件)要相互通信,双方必须使用同一种“语言”,这样才能理解彼此。这种双方必须遵守一致的规则就称为协议(Protocal)。

image.png

狭义的TCP/IP指作用于传输层的TCP协议和网络层的IP协议,广义的TCP/IP则是指上图中的协议族。

TCP/IP协议族的分层设计

image.png

要解决网络数据传输这一个大的命题,需要引入分层的概念,分层有以下好处:

  1. 模块化设计范式:责任边界清晰化,每层只需关注本层核心职责。接口标准化,不同厂商的设备可以实现互操作。
  2. 技术演进自由度:赋予每层独立升级的能力,其它层无需修改。协议替换灵活性,例如从HTTP1.1升级到HTTP3时,只需要在传输层进行TCP->QUIC的替换,在应用层的HTTP语义不需要修改。
  3. 复杂度管控体系:分层抽象机制,每层只需要理解相邻层的接口,降低全局认知负荷,如下文的数据封装流程。故障隔离能力,使用不同工具排查各层的问题,物理层:电缆测试仪,数据链路层:arping, tcpdump,网络层:traceroute, mtr,传输层:telnet, nc,应用层:curl, postman。
# 应用层数据
"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" 

# 传输层添加 TCP 头
|TCP头| 源端口:1234 目的端口:80 序号:100 确认号:0|

# 网络层添加 IP 头
|IP头| 源IP:192.168.1.2 目的IP:93.184.216.34|

# 数据链路层添加帧头
|以太网头| 源MAC:00:1A:2B:3C:4D:5E 目的MAC:00:0C:29:XX:XX:XX|
  1. 开发效率提升:应用开发者只需要调用高层API,无需从拉电缆开始实现完整协议栈。异构系统互操作,实现诸如Android-Linux-iOS的跨平台通信。

虽然分层带来显著优势,但也需权衡以下问题:

  1. 性能损耗:多层封装/解封装增加处理延迟
  2. 功能冗余:某些场景可能跨层优化更高效(如 RDMA 绕过 TCP/IP 协议栈)
  3. 抽象泄漏:底层细节可能影响上层表现(如 MTU 分片影响 HTTP 性能)

TCP的三次握手与四次挥手

重温一下经典的高频考点。

1、三次握手:建立连接的 "电话确认"

想象你想和朋友视频聊天,需要先确认对方在线且准备好:

  1. 你发消息问:"在吗?能视频吗?"
    → 客户端发送 SYN(我要连接啦)
  2. 朋友回复:"在的,可以开始!"
    → 服务端回复 SYN-ACK(收到,我也准备好了)
  3. 你立刻说:"好,那我开摄像头了!"
    → 客户端发送 ACK(确认,开始传输数据)

为什么需要三次?
如果第二步后你直接开始视频(少一次确认),可能朋友手机突然没电,导致你对着空气说话。多一次确认能确保双方都真正就绪

2、四次挥手:结束对话的 "礼貌道别"

视频结束后,你们要挂断,但得确保双方都没话说了:

  1. 你说:"我说完啦,先挂了?"
    → 客户端发送 FIN(我要断开啦)

  2. 朋友立刻回应:"好的,我听到了!"
    → 服务端回复 ACK(收到你的挂断请求)

    (此时你停止说话,但朋友可能还有话要说)

  3. 朋友接着说:"对了,明天记得带伞!"
    → 服务端处理完数据后发送 FIN(我也说完了)

  4. 你最后确认:"知道了,拜拜!"
    → 客户端回复 ACK(确认断开)

为什么需要四次?
因为断开连接时,双方都要确认各自的数据都传输完毕。就像挂电话前,双方都要确认对方没话说了才能安心挂断。


以上便是HTTP协议存在的价值,作为TCP/IP协议族里的一员,HTTP协议负责应用层的数据编码和解析。

URI(Uniform Resource Identifier)与URL(Uniform Resource Location)

URI 用字符串标识某一互联网资源,而 URL表示资源的地点(互联网上所处的位置)。可见 URL是 URI 的子集。下图这些不同类型的标识符,都是URL。

image.png

HTTP协议主要解决什么问题

  1. 意图解析:这一次请求的目的是什么,是要提交、读取、更新还是删除 —— 请求方法
  2. 状态同步:请求的结果是成功、失败、部分成功还是其它状态 —— 响应状态码
  3. 对请求本身的描述:本次请求的数据量是多少,请求什么类型的资源,数据格式是怎样的 —— 请求头当中的MINE
  4. 优化数据传输:缓存、压缩、断点续传 —— 请求头中的压缩方法
  5. 安全性:加密、认证 —— HTTPS

HTTP协议设计思想

本节中会挑选HTTP协议设计中的一些精妙之处和核心思想进行记录,如有遗漏,纯属笔者功力不逮。

CS架构设计

在HTTP协议中,一定存在着客户端Client和服务端Server的角色,这两个角色可以互换。客户端负责请求,而服务器负责响应。一个最简单的请求-响应模型如下所示。

image.png

可以看到请求报文由以下5个部分组成。

  1. 请求方法
  2. 请求URI
  3. 协议版本
  4. 请求头
  5. 内容主体

image.png

与之对应的,响应也由5部分组成。(把请求方法+URI换成了状态码+短语)

  1. 协议版本
  2. 状态码
  3. 状态码短语
  4. 响应头
  5. 响应主体

image.png

告知服务器意图的HTTP方法

方法method是指客户端发送请求的意图,是请求Request的必备字段。

image.png

最常用的便是GET、POST方法。PUT、DELETE这两个方法,由于它们在HTTP1.1中不带有验证机制,任何客户端都可以自由上传、删除,因此多数Web网站不支持这两个方法。

告知响应结果的状态码

状态码是一个三位数字,第一位表示大类,共分为5大类,从1XX到5XX,问题程度依次加重。

image.png

2XX成功

表示请求被正常处理了。

  • 200 OK:最常见,请求成功
  • 204 No Content:返回报文中不含主体,适用于客户端需要向服务器发送数据,服务器无需返回数据的场景
  • 206 Partial Content:范围响应,适用于客户端发送了范围请求(请求头里面的Content-Range来指定范围)

3XX 重定向

通常用于浏览器,表示浏览器需要执行某些特殊处理以正确处理请求。

  • 301 Moved Permanently:永久性重定向,所请求的资源已被分配了新的URI,以后都应该使用新的URI来访问该资源
  • 302 Found:临时性重定向,在本次会话中使用新的URI来访问资源
  • 303 See Other:请求的资源存在另一个URI,且应当使用GET方法访问资源
  • 304 Not Modified:只适用于GET请求,当客户端发送请求时含有附带条件(If-Match, If-Modified-Since, If-None-Match, If-Range, If-Unmodified-Since中任意一个)时,表示服务器资源未变,客户端客户直接使用未过期的缓存。该响应不包含主体
  • 307 Temporary Redirect:跟302等价

4XX 客户端错误

  • 400 Bad Request:请求报文里存在语法错误。
  • 401 Unauthorized:表示请求需要有通过HTTP认证的认证信息。
  • 403 Forbidden:对资源的访问被服务器拒绝了。
  • 404 Not Found:服务器上没有请求的该URI的资源。

5XX 服务器错误

  • 500 Internal Server Error:服务器在响应请求时发生内部故障,无法处理该请求。
  • 503 Service Unavailable:服务器超负载或者停机维护中,无法处理任何请求。

HTTP报文首部(头、Header)简介

HTTP首部是HTTP请求和响应中的必传信息,对于应用开发者来说,大部分首部信息是无需关注的,通常已经由网络框架进行处理。

首部的结构是 Key: Value,例如表示报文主体对象类型的Content-Type首部。

Content-Type: text/html

其中Value可以由多个值,例如下面:

Keep-Alive: timeout=15, max=100

如果首部里面的Key重复出现了,这种情况在规范中尚未明确定义,不同的浏览器内部处理逻辑可能存在不同。

HTTP的四种首部

根据实际用途来区分,HTTP首部字段可以分为四种类型:

  • 通用首部字段:请求和响应双方都会使用的字段。

image.png

  • 请求首部字段:请求中使用,补充请求附加内容、客户端信息、响应内容优先级等信息。

image.png

  • 响应首部字段:响应中使用,补充响应的附加内容。

image.png

  • 实体首部字段:针对请求和响应的实体所使用的首部字段,补充资源内容更新时间等实体相关信息。

image.png

以上四种首部,在HTTP/1.1协议中共计47个,硬记也记不住,用的时候查表就行。只需要知道这些首部可以用于控制缓存行为、设定匹配规则、设置访问资源局部范围、传输Cookie、设置实体长度编码语言等信息。

此外,还有HTTP/1.1标准以外但已经广泛使用的Cookie相关首部字段,如下所示:

image.png

服务器在响应中通过Set-Cookie将Cookie发送给客户端,客户端在后续的请求首部里通过Cookie进行传输。

HTTPS——HTTP的安全升级版

在安全方面,HTTP协议存在以下不足:

  • 通信使用明文(不加密),内容可能会被窃听。——对应加密
  • 不验证通信方的身份,因此有可能遭遇伪装。——对应认证
  • 无法证明报文的完整性,所以有可能已遭篡改。——对应完整性保护

针对以上三个不足,业界推出了HTTPS,可以说HTTPS=HTTP+加密+认证+完整性保护。HTTPS本身不是新的协议,而是HTTP通信接口部分用SSL(Secure Socket Layer)和TLS(Transport Layer Security)协议代替的产物。简言之,HTTPS就是身披SSL协议这层外壳的HTTP。SSL协议赋予了HTTP加密、认证、完整性校验的功能。

image.png

HTTPS的混合加密机制

HTTPS采用非对称加密+对称加密的混合加密机制。所谓非对称加密,是指加密和解密过程采用的是不同的密钥。客户端使用服务端的公钥进行加密,该信息传输给服务端后,服务端用其私钥对信息进行解密。在这个过程中,公钥是可以发布在互联网上,被任何人获取到的。而用于解密的私钥则需要由服务端严加看管。

image.png

对称加密则是客户端/服务器使用同一个密钥进行加解密,它的性能更高,但在安全性方面比不过非对称加密。

image.png 因此,常规的做法是,客户端-服务器开始建立连接时,通过非对称加密,客户端将自身的密钥发送给服务器。当服务器获取到该密钥时,双方切换为对称加密,使用这一个相同的密钥进行加解密。

书中使用的是“公开密钥加密”和“共享密钥加密”,我认为“非对称加密”、“对称加密”更加形象。

image.png

首个密钥传输问题

在上述的流程里,存在一个根本的问题:首个密钥(服务器的公钥)要如何安全地交付给客户端? 在双方都没有对方公钥的情况下,一定会面临“先有鸡还是先有蛋”的问题。如果通过明文传输,这中间就存在被篡改的风险。因此需要一个在互联网语境下,让所有的客户端、服务器都认可的可信第三方来做这件事,这就是证书机构。

数字证书认证机构(CA,Certificate Authority)和其相关机关颁发的公开密钥证书,会被内置在浏览器当中。服务器会将自身的发送给数字认证机构,由数字认证机构用机构私钥进行加密后,返回给服务器,称为“证书”。在建立通信的过程中,服务器将证书发送给客户端,客户端再用机构的公钥(前文讲过这个机构公钥会被内置在客户端的浏览器中)进行解密验证无误,便可认为这是可信的服务器公钥。随后进行非对称加密,将自身会话私钥发送给服务器。

image.png

需要指出的是,虽然现在普遍使用TLS,但很多人仍习惯称SSL。实际上SSL已过时,存在安全漏洞,推荐使用TLS。

通过上述证书派发、加解密的过程,得以完成身份认证、数据加密和完整性校验。要注意在这个过程中只对服务器的身份进行了校验,因为初始证书必须经过证书机构进行签名,这个签名的过程是按照证书个数进行收费的,显然对于一般的网页访问场景,不应当也不适合对客户端进行收费。

而在对客户端要求严格的场景下,例如登录网上银行,就必须采用客户端证书对客户端的身份进行验证,U盾便是客户端证书的一种。

HTTP协议未来的发展方向

HTTP/1.1问世于1997年,在26年的发展历程中,它被广泛使用,但他也存在一些缺点:

  • 队头阻塞: 当一个请求因为某种原因被阻塞时,后续的请求也会被阻塞,导致性能下降。
  • 缺乏灵活性: HTTP/1.1 在设计时没有考虑到移动互联网等新兴应用场景,因此在处理大量并发连接时效率较低。

为了解决 HTTP/1.1 的问题,HTTP/2 在 2015 年发布。HTTP/2 引入了多路复用、头部压缩等技术,大大提高了网络传输效率。但是,HTTP/2 仍然基于 TCP 协议,而 TCP 协议存在一些固有的问题,例如拥塞控制和队头阻塞。

为了进一步提高网络传输效率,HTTP/3 在 2020 年发布。HTTP/3 基于 QUIC 协议,QUIC 协议是一种新的传输层协议,它具有以下优点:

  • 减少延迟: QUIC 协议使用 UDP 协议进行数据传输,减少了 TCP 协议的握手和重传等开销,从而降低了延迟。
  • 提高可靠性: QUIC 协议具有前向纠错等机制,可以在一定程度上提高数据传输的可靠性。
  • 更好的移动性: QUIC 协议可以在不同的网络环境下保持连接,从而提高移动互联网用户的体验。

由于 HTTP/3 具有诸多优点,因此它被认为是 HTTP 协议未来的发展方向。目前,HTTP/3 已经被一些主流浏览器和网站所支持,例如 Chrome、Firefox、Google 等。随着时间的推移,HTTP/3 将会得到越来越广泛的应用。

附:使用Charles软件抓包的基本原理与攻防

image.png

在客户端软件开发中,Charles是常用的抓包软件。对于<7.0的设备而言,直接导入Charles证书就可以在PC上对Android App进行抓包。而对于>=7.0的设备,则需要root或者是在debug包里配置允许抓包的属性,才可以进行抓包。这背后的原理是怎样的?为什么对于有些APP即使进行了证书劫持,仍然无法在charles中看到HTTPS请求的明文?

中间人劫持攻击

image.png

Charles代理软件,本质是通过受控的中间人攻击,对HTTPS数据进行解密,其核心流程如上图所示。通过Charles根证书来签发一个伪造的服务器证书,并将该伪造证书发送给客户端,通过root/植入证书的方式,获取客户端信任。该伪造证书实际保存了Charles自身的密钥。

这样,Charles就可以使用自身私钥来破解得到客户端用于对称加密的公钥,从而解析客户端的HTTPS流量。对于Charles-Server这条链路,Charles将自身伪造为客户端,然后用自身的(对称加密)密钥作为客户端密钥传输给服务器,后续自然可以用此密钥对服务器信息进行解密。

Android开发过程中如何应对中间人劫持攻击

针对上文的中间人攻击,安全要求高的App需要采取复合手段进行防护,按照技术所处的层级不同,可以分为以下几种。

  • 常规防护: SSL证书固定 + 禁用代理 + 强制TLS1.3,已经满足安全性要求一般的聊天软件
  • 高阶防护: mTLS双向认证 + Native证书校验 + 数据二次加密,适用于金融、政务等敏感场景

1. 网络层防护

方案实现方式优缺点
SSL证书固定使用OkHttpCertificatePinnerNetwork Security Configuration文件✅ 有效防中间人攻击 ❌ 需定期更新证书,灵活性差
禁用代理/VPN检测ProxyInfoVpnService状态,拦截非可信网络环境✅ 简单有效 ❌ 用户可能依赖代理/VPN
强制TLS 1.3+协议配置网络库(如OkHttp)仅支持TLS 1.3+✅ 防止协议降级攻击 ❌ 旧设备兼容性差

2. 数据层防护

方案实现方式优缺点
双向认证(mTLS)服务端验证客户端证书合法性✅ 极高安全性 ❌ 证书分发和管理复杂
数据二次加密敏感数据用AES-256或国密算法加密后再传输✅ 即使抓包也无法解密 ❌ 加解密性能损耗

3. 代码层防护

方案实现方式优缺点
Native证书校验用C++实现证书校验逻辑,通过JNI调用✅ 防Java层Hook ❌ 需熟悉NDK开发
反调试/反Hook集成ProGuardR8混淆,检测Frida/Xposed等工具✅ 增加逆向难度 ❌ 无法完全防御