目录

网络-00 一个请求的完整旅程

“在浏览器地址栏输入一个网址,按下回车,到页面显示出来,中间发生了什么?”

这是网络方向最经典的面试题。它的价值在于可以无限深挖——面试官可以从任意一个环节切进去追问细节,所以它既是一道题,也是整个知识体系的索引。

本文按时间顺序走完这条链路,每一步都指向系列里对应的深入篇章。这一篇是地图,不是细节

1. 全流程概览

① URL 解析与预处理          ── 浏览器
② 检查缓存                  ── 强缓存命中则直接结束
③ DNS 解析 → IP             ── 网络-11
④ 建立 TCP 连接(三次握手) ── 网络-07
   └ 需要 ARP 拿到网关 MAC   ── 网络-02
⑤ TLS 握手(HTTPS)         ── 网络-16 / 17
⑥ 发送 HTTP 请求            ── 网络-12
⑦ 服务端处理并返回响应      ──
⑧ 浏览器解析响应、渲染页面  ──
⑨ 连接的复用与关闭          ── 网络-07 / 15

2. ① URL 解析与预处理

浏览器拿到你输入的内容后,先要判断这到底是不是一个 URL

  • 输入 github.com → 补全成 https://github.com
  • 输入 如何学习网络 → 判定为搜索词,拼接成默认搜索引擎的查询 URL;
  • 含非 ASCII 字符的域名(如 中文.com)→ 通过 Punycode 转换成 xn--fiq228c.com,因为 DNS 只支持 ASCII;
  • 路径和查询参数里的特殊字符 → URL 编码(percent-encoding)。

然后拆解出 scheme、host、port、path、query(fragment 留在本地,不会发送)。URL 各部分的含义见 网络-12

HSTS 检查:如果这个域名在浏览器的 HSTS 列表里(服务端此前通过 Strict-Transport-Security 头声明过"我只用 HTTPS"),浏览器会在发出请求前就把 http:// 强制改写为 https://。这一步发生在本地,不产生任何网络流量——它的意义是消灭"首次 HTTP 请求被劫持"的窗口。

3. ② 检查缓存

在动网络之前,先查本地有没有可用副本:

  • 强缓存命中Cache-Control: max-age 未过期)→ 直接使用,整个流程到此结束,一个字节都不发;
  • 需要协商 → 带上 If-None-Match / If-Modified-Since 继续后面的流程,可能拿到 304

细节见 网络-13 HTTP 缓存。这是性能优化里收益最大的一环——命中强缓存的请求,后面 7 步全部省掉

4. ③ DNS 解析

拿到域名,需要换成 IP。查找顺序是一条逐级放大的缓存链

浏览器缓存 → 操作系统缓存 → hosts 文件 → 本地 DNS(递归)
                                            └→ 根域 → TLD → 权威服务器(迭代)

绝大多数请求在前几层缓存就返回了。完整过程、递归与迭代的分工、TTL 的坑见 网络-11 DNS

这一步的常见故障:DNS 解析慢是"网页打开慢"最容易被忽略的原因,因为它发生在任何业务代码之前。用 curl -w "%{time_namelookup}" 可以单独量出这段耗时(见 网络-12 的 curl 小节)。

5. ④ 建立 TCP 连接

有了 IP,接下来要建立连接。但在发出第一个 TCP 包之前,还有一个常被跳过的环节。

5.1 先要确定往哪台机器发

主机用子网掩码判断目标 IP 是否在同一网段(网络-03):

  • 同网段 → 通过 ARP 拿到目标主机的 MAC(网络-02);
  • 不同网段 → 通过 ARP 拿到默认网关的 MAC,把包交给网关(网络-05)。

这里是那个高频考点:数据帧的目的 MAC 填的是网关的 MAC,而 IP 首部的目的 IP 始终是最终目标。IP 负责端到端寻址(全程不变),MAC 负责逐跳转发(每经过一个路由器就重写)。

5.2 三次握手

客户端 ──── SYN (seq=x) ────────────────► 服务端
客户端 ◄─── SYN+ACK (seq=y, ack=x+1) ─── 服务端
客户端 ──── ACK (ack=y+1) ─────────────► 服务端
                                    连接建立,耗时 1 RTT

握手由内核自动完成,完成后连接进入 accept 队列等应用 accept() 取走。为什么是三次、队列满了会怎样,见 网络-07 TCP 连接管理

这一步的耗时是 1 个 RTT。跨国访问时 RTT 可能 200ms 以上,这也是后面 HTTP/3 要把握手压缩到 0-RTT 的动力。

6. ⑤ TLS 握手(HTTPS)

如果是 HTTPS,TCP 建立后还要再握一次手,协商出加密密钥。

协议版本 额外耗时
TLS 1.2 2 RTT
TLS 1.3 1 RTT,会话恢复可 0-RTT

核心步骤:交换随机数 → 验证证书(沿证书链一直校验到操作系统内置的根证书)→ 协商出会话密钥 → 之后用对称加密通信。

证书验证、CA 体系、中间人原理见 网络-16 HTTPS 与 TLS;TLS 1.3 的改进和前向保密见 网络-17

到这里累计延迟:DNS + TCP 1 RTT + TLS 1~2 RTT。这就是为什么"首次访问慢,后面快"——后续请求可以复用连接,把这些成本全部省掉。

7. ⑥ 发送 HTTP 请求

GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 ...
Accept: text/html,application/xhtml+xml
Accept-Encoding: gzip, deflate, br
Cookie: session_id=abc123

几个关键点:

  • Host 头是必需的——服务器靠它区分同一 IP 上的多个站点(网络-12);
  • Cookie 自动携带——浏览器根据域名匹配自动附上,这既是便利也是 CSRF 的根源(网络-14);
  • 请求要经过分层封装:HTTP 报文 → TCP 段 → IP 包 → 以太网帧(网络-01)。

8. ⑦ 服务端处理

请求到达服务端后的典型路径:

负载均衡 (LB) → 反向代理 (Nginx) → 应用服务 → 缓存/数据库

这一段是后端的领域,网络视角需要关注的是它可能返回什么

  • 200 正常,304 缓存有效,301/302 重定向(浏览器会回到第 ① 步重新走一遍全流程);
  • 502 后端挂了、504 后端太慢、503 主动拒绝——这三个的区分是排障基本功,见 网络-12

注意 3xx 重定向意味着整条链路重来一次。一次多余的重定向 = 又一轮 DNS + TCP + TLS,这是为什么要尽量减少重定向跳数。

9. ⑧ 浏览器渲染

拿到 HTML 后,浏览器的工作大致是:

HTML → 解析 → DOM 树 ┐
                     ├→ 渲染树 → 布局(Layout) → 绘制(Paint) → 合成(Composite)
CSS  → 解析 → CSSOM ┘

从网络角度需要理解的是资源加载的阻塞关系

  • CSS 阻塞渲染——不下载完不会绘制(避免闪烁未样式化的内容);
  • JS 默认阻塞解析——因为脚本可能修改 DOM,浏览器不敢继续往下解析。用 defer / async 可以解除阻塞;
  • 解析过程中遇到 <img><script><link>发起新的请求——每一个都要重走前面的流程(但通常能复用连接)。

所以一个页面的实际网络行为是几十到上百个请求,而不是一个。这正是 HTTP/2 多路复用要解决的问题(网络-15)。

10. ⑨ 连接的复用与关闭

HTTP/1.1 默认长连接Connection: keep-alive),一条 TCP 连接可以连续发多个请求,省掉重复握手。但它有队头阻塞问题——响应必须按请求顺序返回。

演进路线(网络-15网络-18):

版本 并发方式 遗留问题
HTTP/1.1 多条 TCP 连接(每域名 6 条) HTTP 层队头阻塞
HTTP/2 单连接多路复用 TCP 层队头阻塞
HTTP/3 QUIC 流级独立 UDP 可能被屏蔽

最终连接通过四次挥手关闭,主动关闭方会进入 TIME_WAIT 等待 2MSL(网络-07)。

11. 一张图串起所有层

                    你的输入
┌──────────────────────────────────────────────┐
│ 应用层   URL解析 → 缓存 → DNS → HTTP 报文    │  网络-11,12,13,14,15
├──────────────────────────────────────────────┤
│ (TLS)    证书验证 → 密钥协商 → 加密          │  网络-16,17
├──────────────────────────────────────────────┤
│ 传输层   三次握手 → 分段 → 可靠传输 → 流控   │  网络-06,07,08,09
├──────────────────────────────────────────────┤
│ 网络层   IP 寻址 → 路由 → 分片               │  网络-03,04,05
├──────────────────────────────────────────────┤
│ 链路层   ARP → 封装成帧 → MAC 逐跳转发       │  网络-02
└──────────────────────────────────────────────┘
                    物理链路

12. 延迟都花在哪了

把这条链路按耗时拆开,是性能优化的起点:

阶段 典型耗时 优化手段
DNS 解析 0~200ms DNS 预解析(dns-prefetch)、长 TTL、本地缓存
TCP 握手 1 RTT 长连接复用、连接预热(preconnect
TLS 握手 1~2 RTT TLS 1.3、会话恢复、OCSP Stapling
请求响应 取决于后端 CDN、缓存、后端优化
内容传输 取决于体积 gzip/br 压缩、图片优化
渲染 关键 CSS 内联、JS 异步加载

用 curl 可以直接量出每一段:

curl -s -o /dev/null -w "DNS:%{time_namelookup} 连接:%{time_connect} TLS:%{time_appconnect} 首字节:%{time_starttransfer} 总计:%{time_total}\n" https://example.com

三个最有效的优化,恰好对应三个不同层次

  1. 命中强缓存 —— 直接跳过全部 9 步(第 ② 步);
  2. 复用连接 —— 跳过 TCP + TLS 握手(第 ④⑤ 步);
  3. 就近接入(CDN) —— 缩短 RTT 本身,等比例改善所有需要往返的环节。

13. 全系列考点地图

按主题分组,链接指向对应篇章。各篇末尾有折叠自测题,可以对照复习。

13.1 分层与链路层

  • 网络分层模型、OSI 与 TCP/IP 的对应、封装与解封装 → 网络-01
  • 以太网帧格式、交换机 MAC 学习、VLAN、ARP 协议与 ARP 欺骗网络-02

13.2 网络层

  • IP 地址结构、CIDR、IPv4/IPv6 首部、NDP 与 Go 双栈监听 → 网络-03
  • MTU 与 MSS 的区别、PMTUD、IPv6 分片与隧道开销 → 网络-04
  • 网关的 MAC 地址(高频)、最长前缀匹配、NAT 与 conntrack → 网络-05

13.3 传输层

  • UDP 特点、TCP 与 UDP 对比与选型、UDP 上的可靠传输 → 网络-06
  • 为什么三次握手 / 四次挥手、TCP 状态机、TIME_WAIT 与 2MSL、半连接与全连接队列、SYN Flood → 网络-07
  • TCP 首部、RTO 与指数退避、SACK粘包与拆包、Go 字节流处理 → 网络-08
  • 滑动窗口、流量控制 vs 拥塞控制、BDP、CUBIC/BBR 与 ECN → 网络-09
  • CLOSE_WAIT / TIME_WAIT 堆积的定位与处置、keepalive、队列与缓冲区参数、BBR网络-10

13.4 应用层

  • 域名分级、递归 vs 迭代查询、记录类型、TTL、DNS 何时用 TCP、DoH/DoT → 网络-11
  • HTTP 报文结构、幂等性GET vs POST状态码体系(301/302/307、401/403、502/503/504)网络-12
  • 强缓存 vs 协商缓存no-cache vs no-storeETag vs Last-Modified网络-13
  • Cookie 属性、Session vs Token vs JWT同源策略CORS 预检CSRF网络-14
  • HTTP 版本演进、队头阻塞(HTTP 层 vs TCP 层)、多路复用、HPACK → 网络-15

13.5 安全与新协议

  • 对称与非对称加密、数字证书与 CA 体系、TLS 握手、抓包与反抓包 → 网络-16
  • TLS 1.3 的改进、1-RTT / 0-RTT、前向保密网络-17
  • QUIC 为什么基于 UDP、连接迁移、QPACK、HTTP/3 部署 → 网络-18

13.6 编程与实践

  • WebSocket 握手与帧格式、与 SSE / 轮询的对比、心跳保活、关闭握手 → 网络-19
  • Socket 不是协议、API 调用流程与 TCP 状态的对应、内核缓冲区、Go netpoller网络-20
  • tcpdump 过滤语法、Wireshark 读包与统计、从包里认出握手/重传/RST、TLS 解密网络-21
  • 按症状索引的排查手册:连不上 / 慢 / 中断 / DNS 异常 / MTU 黑洞、工具速查表 → 网络-22
  • Go net/http 生产实践:连接池、分层超时、安全重试、服务端防护与优雅退出 → 网络-23

13.7 高频题速查

如果时间紧,这些是出现频率最高的:

题目 篇章
从输入 URL 到页面显示发生了什么 本文
为什么三次握手、四次挥手 07
TIME_WAIT 为什么等 2MSL 07
TCP 如何保证可靠传输 08
流量控制和拥塞控制的区别 09
TCP 和 UDP 的区别与选型 06
大量 CLOSE_WAIT / TIME_WAIT 怎么排查 10
GET 和 POST 的区别 12
强缓存与协商缓存 13
跨域是什么,CORS 怎么解决 14
HTTPS 如何保证安全 16
HTTP/2 解决了什么,还剩什么问题 15 / 18
Go HTTP 客户端为什么必须复用 Transport 23
接口变慢/连不上怎么排查 22

14. 本章面试题

从输入 URL 到页面显示,完整讲一遍

九个阶段:

  1. URL 解析 —— 判断是否为 URL、Punycode 转换、URL 编码、HSTS 检查(本地把 http 改写为 https);
  2. 检查缓存 —— 强缓存命中则直接结束,一个字节都不发;
  3. DNS 解析 —— 浏览器缓存 → 系统缓存 → hosts → 本地 DNS(递归)→ 根/TLD/权威(迭代);
  4. 建立 TCP 连接 —— 先用子网掩码判断是否同网段,通过 ARP 拿到目标或网关的 MAC,然后三次握手(1 RTT);
  5. TLS 握手 —— 验证证书、协商密钥(TLS 1.2 为 2 RTT,1.3 为 1 RTT);
  6. 发送 HTTP 请求 —— 带 Host、Cookie 等头部;
  7. 服务端处理 —— LB → Nginx → 应用 → 数据库,返回状态码;
  8. 浏览器渲染 —— HTML/CSS 解析成 DOM/CSSOM → 渲染树 → 布局 → 绘制;
  9. 连接复用与关闭 —— keep-alive 复用,最后四次挥手。

加分点:说清 ARP 那一步(很多人漏)、指出 3xx 重定向会让整条链路重来、说出每步的 RTT 成本。

这个过程中的延迟主要在哪几段?怎么优化?

成本拆解:DNS(0~200ms)+ TCP 握手(1 RTT)+ TLS 握手(1~2 RTT)+ 服务端处理 + 内容传输。

三个最有效的优化,对应三个层次

  1. 命中强缓存 → 跳过全部流程(收益最大);
  2. 复用长连接 → 跳过 TCP + TLS 握手;
  3. CDN 就近接入 → 缩短 RTT 本身,等比例改善所有往返环节。

其他:TLS 1.3 省一个 RTT、dns-prefetch / preconnect 预热、gzip/br 压缩、减少重定向跳数。

curl -w "%{time_namelookup} %{time_connect} %{time_appconnect} %{time_starttransfer}" 可以直接量出每段耗时。

为什么"首次访问慢,后续访问快"?

首次访问要付全部固定成本:DNS 解析 + TCP 三次握手(1 RTT)+ TLS 握手(1~2 RTT)。

后续请求:

  • DNS 结果已被缓存;
  • TCP 连接通过 keep-alive 复用,不再握手;
  • TLS 可用会话恢复(TLS 1.3 甚至 0-RTT);
  • 静态资源可能直接命中强缓存,完全不发请求。

所以首次的延迟主要是协议握手成本,而非带宽不足。

请求发出前,浏览器怎么知道往哪台机器发数据帧?

分两步,这是最容易漏答的环节:

  1. 用子网掩码与目标 IP 做与运算,判断是否同网段;
  2. 同网段 → ARP 拿到目标主机 MAC;不同网段 → ARP 拿到默认网关的 MAC

关键结论:帧首部的目的 MAC 是网关的 MAC,而 IP 首部的目的 IP 始终是最终目标。IP 端到端寻址(全程不变),MAC 逐跳转发(每跳重写)。

详见 网络-02网络-05

一个页面为什么会发出几十个请求?这带来什么问题?

浏览器解析 HTML 时,遇到 <img><script><link>、字体等资源引用就会发起新请求,一个页面通常有几十到上百个。

带来的问题:HTTP/1.1 下每个域名最多 6 条并发连接,请求排队等待,且每条连接都有握手成本。这正是:

  • HTTP/1.1 时代要做雪碧图、域名分片、资源合并的原因;
  • HTTP/2 引入多路复用要解决的问题(单连接并发多个流);
  • HTTP/3 换成 QUIC 的原因(HTTP/2 仍受 TCP 层队头阻塞影响)。

详见 网络-15网络-18