Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

网络协议

网络是中级面试必考硬通货. 如果你有风控, 抓包对抗或 TLS 相关的可核验经历, 可用 HTTPS, 证书, TLS 以及中间人防护, 证书校验, 双向认证等内容说明经验边界; 否则按本篇知识点和练习证据准备.

本篇含知识点讲解 + 高频面试题.

一, HTTP 基础

  • 无状态: 每次请求独立, 靠 Cookie/Session/Token 维持状态.
  • 请求结构: 请求行 (方法 + URL + 版本)+ 请求头 + 空行 + 请求体.
  • 常用方法: GET (查, 幂等), POST (增, 非幂等), PUT (全量改, 幂等), DELETE, PATCH (部分改), HEAD, OPTIONS (预检).
  • GET vs POST: 两者首先由方法语义区分, 不是 “参数放哪” 的固定规则. GET 通常用于安全, 幂等的资源读取, 请求内容常编码在 URI / 查询参数中; 实际 URI 长度受客户端, 代理和服务端实现限制, HTTP 规范没有一个通用固定上限. POST 用于让目标资源按请求内容执行处理, 默认不幂等, 但可以通过明确的新鲜度信息和缓存键被缓存; 请求体也受服务器, 网关, 客户端和业务配置限制, 不能说 “无长度限制”.

状态码

  • 1xx 信息;2xx 成功 (200, 201, 204).
  • 3xx 重定向: 301 (永久), 302 (临时), 304 (协商缓存命中).
  • 4xx 客户端错: 400, 401 (未认证), 403 (无权限), 404, 405, 429 (限流).
  • 5xx 服务端错: 500, 502 (网关错误), 503 (不可用), 504 (网关超时).

逐码的排障定位, 重试与退避策略见 见 30.

缓存

  • 强缓存: Cache-Control(max-age), Expires, 不发请求直接用本地.
  • 协商缓存: ETag/If-None-Match, Last-Modified/If-Modified-Since, 发请求由服务端判断, 命中返 304.

报文逐行解读与登录态边界

下面是数字示例, 用于解释一对 HTTP/1.1 POST/200 报文, 非可直接执行代码.

POST /v1/sessions HTTP/1.1
Host: api.example.test
Accept: application/json
Content-Type: application/json
Content-Length: 15

{"email":"a@b"}

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 11
Cache-Control: no-store

{"ok":true}

请求行给出方法/目标/版本; Host 路由虚拟主机; Content-Type 说明 body 表示; 请求 JSON 的 UTF-8 字节数为 15, 因此 Content-Length: 15. 响应 body {"ok":true} 是 11 字节, 故为 Content-Length: 11. no-store 禁止保存敏感响应; no-cache 是复用前重验证. max-age 到期后可携带 ETag 的 If-None-Match, 匹配时 304 且复用旧 body.

HTTP/1.1 也可用 Transfer-Encoding: chunked: 每块以十六进制长度, CRLF, 数据, CRLF 传输, 最后以 0 块结束. 接收端不得同时依赖 Content-Length 和 Transfer-Encoding 定界: CL/TE 冲突可能导致 request smuggling, 应按 RFC/网关策略拒绝或规范化. 没有 CL/TE 时响应可由连接关闭定界, 但不适用于可复用连接. HTTP/2/3 使用各自帧层, 不使用 HTTP/1.1 chunk framing; 204, 304 和对 HEAD 的响应不得带 message body.

Cookie 是客户端随匹配域 / 路径规则自动附带的状态载体; Session 是服务端用 cookie 值关联的状态; Token 是客户端显式放入如 Authorization: Bearer <ACCESS_TOKEN> 的凭据格式, 未必天然无状态. 移动端应使用 HTTPS, 限制 token 生命周期和刷新流程, 日志只保留是否存在 / 哈希或长度等诊断信息, 不能输出原文.

Cookie 的 Domain 决定可发送的主机范围, 省略时为 host-only; Path 限制路径但不是访问控制; Secure 仅经 HTTPS 发送; HttpOnly 阻止脚本读取; SameSite 限制跨站自动携带; Expires/Max-Age 决定持久期. 登录成功, 提权和密码变更后轮换 session ID, 防 session fixation.access token 应短期, 仅通过 TLS 发送; refresh token 仅在受控刷新端点使用, 可轮换/撤销, 移动端放在按威胁模型选择的受保护存储而不是日志/URL. 登录, 刷新, 注销以关联 trace 记录事件结果和 token 版本: 登录签发 access/refresh, access 过期仅走单一刷新流程, 刷新失败或注销即撤销 refresh 并清除本地凭据; 不能记录 token 原文. 撤销 refresh 和删除本地凭据不会使已经签发的自包含 access token 立即无效, 默认只能等它到期; 高风险系统应使用更短 TTL, 并按风险采用 denylist, token version 校验或可撤销的引用 token. Cookie 自动附带时需防 CSRF; 将 token 置入可被脚本读取的位置会扩大 XSS 泄漏风险; 二者都不能被 “使用 HTTPS” 替代.

自测: (1) 用 curl --raw 向测试服务发送 chunked body, 预期服务按块重组; (2) 发送 CL/TE 冲突报文, 预期网关拒绝而非转发歧义请求; (3) 登录后检查 session 轮换, 注销后 refresh token 被拒绝, 日志只含 trace 和结果.

二, TCP/IP 分层与数据封装

TCP/IP 是面向实际网络通信的四层抽象, 与 OSI 七层模型不是逐层一一对应的关系. 例如 OSI 的会话层和表示层常由 TCP/IP 应用层协议或应用程序承担, 排障时应先说明所用模型, 不要把两者硬性等同.

TCP/IP 层主要职责常见协议或机制数据单元
应用层定义业务语义, 消息格式和应用认证HTTP, HTTPS, DNS, WebSocket数据 / 报文
传输层端到端进程通信, 端口复用与传输语义TCP, UDP, QUICTCP 段 / UDP 数据报 / QUIC 包
网际层跨网络寻址与路由转发IP, ICMPIP 数据报
网络接口层在本地链路上传送帧Ethernet, Wi-Fi, ARP帧

一次 HTTPS 请求的封装可按下列路径理解: 应用数据先形成 HTTP 报文, 通常交给 TLS 记录层保护, 再由 TCP 分段, 封装进 IP 数据报和链路帧. 接收端按相反方向解封装. HTTP/3 的路径不同: HTTP/3 报文由 QUIC 承载, QUIC 包再进入 UDP 数据报; QUIC 在用户态实现连接, 可靠传输, 流控制和流的有序交付等能力, UDP 只提供无连接的数据报承载.

HTTP/1.1 或 HTTP/2 over HTTPS:
HTTP data -> TLS records -> TCP segments -> IP packets -> link frames

HTTP/3:
HTTP/3 data -> QUIC packets -> UDP datagrams -> IP packets -> link frames

HTTPS, TCP, UDP 与 Socket 的边界

HTTPS 是 HTTP 叠加 TLS 的应用层协议. TCP 和 UDP 是传输层协议. Socket 不是网络协议, 而是操作系统提供的编程接口抽象: 应用通过 socket 选择地址族和传输类型, 再读写字节流或数据报. 一个常见的 HTTPS 客户端通常使用 TCP socket; 支持 HTTP/3 的客户端则使用 UDP socket 与 QUIC 栈通信.

对象所在抽象层连接与交付语义加密常见适用场景
HTTPS应用层HTTP 语义; 通常经 TLS over TCP 可靠有序传输, HTTP/3 时经 QUICTLS 提供登录, 支付, API 和网页
TCP传输层面向连接, 可靠, 有序字节流不自带文件传输, 传统 HTTP/HTTPS
UDP传输层无连接数据报, 不保证到达, 顺序或去重不自带DNS, 实时音视频的媒体数据, QUIC 承载
SocketOS 编程接口取决于选择 TCP, UDP 或其他协议族取决于上层协议客户端, 服务端和本地进程间通信

不能因为 UDP 不提供 TCP 的可靠性保证就称 UDP “不安全”: 机密性和身份认证由 TLS 等安全协议决定, 可靠性, 顺序和拥塞控制也可以由 QUIC 或应用协议按业务需求实现. 反过来, TCP 可靠有序也不等于加密; 未叠加 TLS 的 TCP 流量仍可能被窃听或篡改.

三, HTTP 版本演进

版本关键特性解决的问题
HTTP/1.0短连接, 每次请求新建 TCP—
HTTP/1.1长连接 (keep-alive), 管线化, Host 头, 分块传输复用连接
HTTP/2二进制分帧, 多路复用 (一个连接并发多请求), 头部压缩 (HPACK)队头阻塞 (应用层)
HTTP/3基于 QUIC over UDP, 0-RTT, 连接迁移TCP 队头阻塞, 握手延迟
  • HTTP/1.1 队头阻塞: 同一连接请求需按序响应, 前一个慢会卡后面. HTTP/2 多路复用在应用层缓解, 但 TCP 层仍有队头阻塞; HTTP/3 基于 QUIC/UDP, 通过独立 stream 降低 TCP 层队头阻塞影响.
  • WebSocket: 提供双向消息通道. HTTP/1.1 常通过 Upgrade 建连; HTTP/2 可使用扩展 CONNECT, HTTP/3 也有相应扩展 CONNECT 机制. 具体客户端/服务端支持需要按协议版本和实现核验, 不能只描述 HTTP/1.1 Upgrade.

四, HTTPS 与 TLS (按证据准备)

HTTPS = HTTP + TLS/SSL, 解决三个问题:加密 (防窃听), 完整性 (防篡改), 身份认证 (防冒充).

TLS 握手: RSA 密钥交换 vs ECDHE

TLS 的核心思想是:先认证身份并协商出对称会话密钥, 后续用对称加密传 HTTP 数据. 对称加密快, 但首次密钥分发困难; 非对称 / 密钥交换负责解决首次协商与身份认证.

维度RSA 密钥交换 (TLS 1.2 旧式)ECDHE 密钥交换 (现代主流)
证书公钥用途客户端用证书里的 RSA 公钥加密 pre-master secret证书用于验证服务端身份; 临时 ECDHE 公钥用于密钥交换
会话密钥来源pre-master secret + 双方随机数派生双方临时椭圆曲线私钥 / 公钥计算共享秘密 + 随机数派生
前向保密没有. 服务端私钥泄露后, 历史抓包可能被解密有. 临时私钥握手后丢弃, 长期证书私钥泄露也难解历史流量
面试风险点容易把 “证书公钥加密密钥” 当成所有 TLS 的固定流程要说清 “证书认证身份, ECDHE 协商密钥”

TLS 1.2 RSA 简化流程

  1. Client Hello: 客户端发支持的 TLS 版本, 加密套件, 随机数.
  2. Server Hello: 服务端选择套件, 返回随机数, 下发证书 (含公钥).
  3. 客户端验证证书 (CA 链, 域名, 有效期, 吊销状态等), 生成 pre-master secret, 用服务端 RSA 公钥加密后发送.
  4. 服务端用私钥解密, 双方用 pre-master secret + client_random + server_random 派生对称会话密钥.
  5. 双方发送 Finished 校验握手完整性, 之后用对称加密通信.

TLS 1.2 ECDHE / TLS 1.3 直觉

  • ECDHE: 服务端发送临时 ECDHE 公钥并用证书私钥签名, 客户端验证签名后也生成临时公钥; 双方各自用 “自己的临时私钥 + 对方临时公钥” 算出共享秘密. 网络上没有直接传输会话密钥.
  • TLS 1.3: 移除静态 RSA 密钥交换等旧套件, 把常规握手压到 1-RTT: ClientHello 携带 key share, ServerHello 返回 key share 和证书相关消息, 双方很快得到密钥.
  • TLS 1.3 握手序列 (1-RTT): ClientHello (含 key_share) → ServerHello (返回 key_share) 连同服务端证书 / CertificateVerify / Finished 一起到达 → 客户端验证证书并回 Finished → 应用数据. 相比 TLS 1.2 完整握手典型 2-RTT 后才能发应用数据, TLS 1.3 把证书与密钥协商结果合并在第一个 RTT 返回, 第二个 RTT 客户端即可发应用数据.
  • 0-RTT: 客户端基于上次会话恢复提前发送早期数据, 降低重连延迟; 边界是早期数据可能被重放, 所以只适合幂等 GET / 查询类请求, 不适合支付, 下单, 转账, 登录态变更等非幂等操作.

面试一句话: 旧 RSA 像 “用证书公钥包住会话密钥”, 现代 ECDHE/TLS 1.3 更像 “证书负责证明你是谁, 临时密钥交换负责生成本次会话密钥”, 因此具备前向保密.

证书与信任链

  • 证书由 CA 逐级签发, 设备内置根 CA. 验证时沿链校验到可信根.
  • 为什么不能只用对称加密? 密钥分发难题: 首次怎么安全传密钥? 用非对称解决.
  • 为什么不全用非对称? 慢. 所以只用它协商对称密钥.

证书校验至少包含: 验证链能否连到受信任锚点, 当前时间是否在有效期, 叶子证书 SAN 是否匹配请求主机名, 签名 / 用途和平台策略是否允许. 吊销检查, CT, 用户安装 CA 与网络安全配置的具体行为受 Android 版本, 网络栈和服务端能力影响. 不要为 “连通” 跳过 hostname verifier 或自定义信任所有证书; 这会把 HTTPS 降回可被中间人替换的明文等价风险.

主机名校验不能省: 即使证书链验证到受信根, 若叶子证书 SAN 不含所请求的 hostname, 也必须拒绝连接. 两步缺一不可: 链验证证明 “证书可信”, 主机名校验证明 “对方就是你要连的域名”, 跳过任一步都可能被中间人替换.

安全实战 (按可核验证据展开)

  • 中间人攻击 (MITM): 攻击者伪造证书. 防御靠客户端严格校验证书.
  • 证书锁定 (SSL Pinning): App 内置服务端证书/公钥指纹, 只信任它, 防抓包/MITM: 风控/金融 App 标配.
  • 双向认证 (mTLS): 服务端也验证客户端证书.
  • 抓包对抗: Charles/Fiddler 可通过安装根证书抓取 HTTPS; App 可用 Pinning + 检测代理对抗. 仅在有可披露, 可核验经历时, 将其作为实战案例说明.

五, TCP / UDP

TCP 三次握手

  1. Client → SYN(seq=x)
  2. Server → SYN+ACK(seq=y, ack=x+1)
  3. Client → ACK(ack=y+1) 为什么三次? 确认双方收发能力都正常; 两次无法确认客户端的接收能力, 且防止历史失效连接请求建立连接.

TCP 四次挥手

  1. Client → FIN 2. Server → ACK 3. Server → FIN 4. Client → ACK 为什么四次? 关闭是双向的, 服务端收到 FIN 后可能还有数据要发, 所以 ACK 和 FIN 分开. TIME_WAIT(2MSL): 主动关闭方等待, 确保最后 ACK 到达 + 让旧报文消散.

可靠性机制

序列号 + 确认应答, 超时重传, 滑动窗口 (流量控制), 拥塞控制.

拥塞控制: 看懂 cwnd / ssthresh 转换

  • cwnd(congestion window): 发送端根据网络拥塞程度维护的拥塞窗口, 限制 “未确认在途数据量”.
  • ssthresh(slow start threshold): 慢启动阈值, 决定从指数增长切到线性增长.
  • 实际发送窗口通常取 min(cwnd, rwnd): 拥塞控制看网络承载能力, 流量控制看接收端缓存能力.
阶段触发 / 进入条件cwnd 变化退出条件
慢启动连接刚建立或超时后重新探测每个 RTT 近似翻倍 (指数增长)cwnd >= ssthresh 转拥塞避免; 或丢包
拥塞避免cwnd 达到 ssthresh每个 RTT 近似 +1 MSS (线性增长)丢包 / 重复 ACK
快重传收到 3 个重复 ACK, 推测某段丢失但网络仍有流动不等超时, 立即重传疑似丢失段进入快恢复
快恢复快重传之后通常把 ssthresh 设为丢包前 cwnd 的一半, cwnd 降低后线性恢复新 ACK 到达后回到拥塞避免

超时 vs 快重传的区别:

  • 超时重传说明网络可能严重拥塞或 ACK 完全回不来, 处理更保守: 常见做法是 ssthresh = cwnd / 2, 然后 cwnd 回到很小值重新慢启动.
  • 3 个重复 ACK 说明后续包还能到达, 网络没有完全断流, 所以只减半窗口并快恢复, 比超时温和.
新连接/超时
  ↓ cwnd 指数增长
慢启动 ── cwnd >= ssthresh ──> 拥塞避免(线性增长)
  │                              │
  └── 超时:ssthresh=cwnd/2,cwnd 重置 ─┘
                                 │
                                 └── 3 dup ACK:快重传 → 快恢复 → 拥塞避免

数字推演 (示意值): 现代 Linux 常见初始 cwnd 为 10 MSS (RFC 6928, 标注为常见默认而非协议强制). 慢启动每个 RTT 近似翻倍: 第 1 个 RTT 后约 20 MSS, 第 2 个约 40 MSS, 第 3 个约 80 MSS. 若 ssthresh 为 64 MSS (示意), 则约在第 3 个 RTT 触达阈值并切到拥塞避免的线性增长; 具体第几个 RTT 取决于 ssthresh 与丢包 / 显式拥塞反馈, 不能当固定值.

面试答题流: 先区分可靠性 (序号/ACK/重传) 与拥塞控制 (保护网络), 再解释 cwnd/ssthresh, 最后用 “超时更严重, 快重传更温和” 讲阶段转换.

TCP vs UDP

TCPUDP
连接面向连接无连接
可靠可靠有序不承诺可靠性
速度慢快
场景HTTP, 文件音视频, DNS, QUIC

高频面试题

Q1: HTTP 和 HTTPS 区别? HTTPS = HTTP + TLS, 提供加密, 完整性, 身份认证. HTTP 默认明文 80 端口, HTTPS 默认加密 443 端口, 需证书, 有握手开销但安全.

Q2: TLS 握手为什么用非对称 + 对称结合? 非对称 / 密钥交换解决首次协商和身份认证, 对称加密负责后续高性能传输. 旧 RSA 是客户端用证书公钥加密 pre-master secret; 现代 ECDHE/TLS 1.3 用临时密钥交换生成会话密钥, 证书主要证明服务端身份, 并提供前向保密.

Q3: TCP 为什么三次握手不是两次? 三次才能确认双方收发能力都正常, 并防止已失效的历史连接请求突然到达导致错误建连. 两次无法确认客户端接收能力.

Q4: TIME_WAIT 是什么? 为什么等 2MSL? 主动关闭方在四次挥手后进入 TIME_WAIT, 等 2 倍报文最大生存时间: 确保最后的 ACK 能到达对端 (否则对端重传 FIN), 并让本连接的旧报文在网络中消散.

Q5: HTTP/2 相比 1.1 的核心改进? 二进制分帧, 多路复用 (一个连接并发多请求, 解决应用层队头阻塞), 头部压缩 HPACK. 服务端推送是早期规范 (RFC 7540) 特性, 但 Chrome 等主流浏览器已移除支持, 不属当前核心特性.

Q6: 什么是 SSL Pinning? 为什么风控 App 要用? 客户端内置服务端证书或公钥指纹, 握手时只信任它而非系统 CA, 防止中间人用伪造证书抓包 / 篡改. 金融, 风控 App 用它对抗抓包和 MITM.

Q7: 输入 URL 到页面展示发生了什么? DNS 解析 → 建立 TCP 连接 (三次握手)→ TLS 握手 (HTTPS)→ 发 HTTP 请求 → 服务端响应 → 客户端解析渲染 → 关闭 / 复用连接.

进阶补充: DNS, QUIC, TCP 状态与 TLS 细节

DNS 解析链路

域名访问前通常经历缓存查询, 本地 DNS, 递归解析. 移动端排查网络慢时要区分 DNS, TCP, TLS, 请求, 响应各阶段.

HTTP/3 与 QUIC

HTTP/3 基于 QUIC, 而 QUIC 运行在 UDP 之上. QUIC 将 TLS 1.3 握手与自身连接建立结合, 并在用户态实现可靠传输, 流级有序交付和拥塞控制; UDP 仍只是底层数据报承载. 这避免了 TCP 丢包导致同一连接所有 HTTP/2 流停顿的问题, 也支持连接迁移. 面试不要把 “UDP 不保证可靠性” 延伸为 “HTTP/3 不可靠” 或 “UDP 不安全”.

TIME_WAIT / CLOSE_WAIT 排障

状态常见原因排查方向
TIME_WAIT 多主动关闭方等待旧包消失连接复用, 服务端参数
CLOSE_WAIT 多本端未 close socket代码资源释放, 连接池

TLS 补充: SNI, ALPN, OCSP, 会话恢复

  • SNI: 客户端握手时告诉服务端目标域名.

  • ALPN: 协商 HTTP/1.1, HTTP/2 等应用协议.

  • OCSP: 检查证书吊销状态.

  • Session Ticket/PSK: 减少重复握手成本.

  • 追问: HTTP/2 和 HTTP/3 都解决什么问题? HTTP/2 多路复用仍受 TCP 队头阻塞影响; HTTP/3 基于 QUIC 改善连接迁移和队头阻塞.