一、为什么这道题能拉开差距

先给结论: 这道题本身没有标准答案,但它能像一面镜子一样,照出候选人知识体系的深度、广度和结构化表达能力。

1.1 初级回答长什么样

大多数候选人的回答基本是这个模板:

用户在浏览器输入 URL,浏览器先解析域名,通过 DNS 找到服务器 IP,然后建立 TCP 连接,发送 HTTP 请求,服务器处理请求并返回 HTML,浏览器渲染页面。

这段话没有错,但每一句话都只是「名词的堆砌」。面试官如果在这里追问一句「DNS 查询具体是怎么查的」「TCP 为什么是三次握手而不是两次」,很多人就卡住了。

1.2 面试官真正想考察什么

阿里的面试官问这道题,本质上是在做一次知识体系的压力测试。他想知道的不是你会不会背流程,而是你对以下四个维度的理解:

  • 广度:你是否知道这条链路上涉及到的所有关键组件,包括浏览器、操作系统、DNS、TCP/IP、TLS、HTTP、负载均衡、网关、后端服务、数据库、CDN、渲染引擎等。

  • 深度:当面试官随便挑一个环节追问时,你能不能继续往下挖三层。比如问「三次握手」,你能不能讲清序列号机制、SYN 队列、SYN Flood 攻击和 TCP Fast Open。

  • 结构化:你能不能把一条很长的链路拆成清晰的阶段,每一阶段先讲目的、再讲过程、最后讲异常情况,让面试官觉得你「想得清楚」。

  • 工程视角:你能不能从「理论」跳到「生产实践」。比如 DNS 解析不只是查一个 IP,还涉及缓存策略、CDN 调度、劫持防护;TCP 不只是握手,还涉及超时重传、拥塞控制;HTTP 不只是请求响应,还涉及连接复用、头部压缩。

所以,这篇文章会沿着「一条完整链路 + 每个环节的工程细节 + 高频追问」来展开。全文会非常长,建议收藏后分阶段阅读。我们把整条链路拆成十个阶段一一击破。

二、从敲下回车开始:浏览器在做什么

很多人以为「输入 URL 到返回请求」是从网络请求开始的,但其实在数据包离开你的电脑之前,浏览器内部已经完成了一系列复杂的处理。理解这一步,才能回答出区别于普通候选人的「第一层差异」。

2.1 你真的输入的是一个 URL 吗

用户在地址栏敲下的东西,不一定是一个合法的 URL。浏览器需要先判断输入内容的类型:

  • 如果输入的是纯域名,比如 baidu.com,浏览器会自动补全协议,默认使用 https://,并加上路径 /。

  • 如果输入的是关键词,比如「淘宝」,浏览器会把它交给搜索引擎,而不是当成 URL 访问。

  • 如果输入包含明显的协议头,比如 http:// 或 https://,则直接按 URL 处理。

这个「输入分类」的过程由浏览器的地址栏(Omnibox)完成,它还会根据历史记录、书签、搜索引擎建议提供联想候选。所以严格来说,面试中说的「输入 URL」,其实暗含了「浏览器已经识别出这是一个合法的 URL」这个前提。

2.2 URL 的完整结构

一个完整的 URL 由以下部分组成:

text

scheme://user:password@host:port/path?query#fragment

以 https://www.example.com:443/path/to/resource?key=value&name=test#section 为例:

组成部分示例值作用
schemehttps协议,决定使用什么方式通信
user:password(本例为空)可选的用户认证信息,现已不推荐使用
hostwww.example.com主机名,需要解析成 IP
port443端口,省略时使用协议默认端口
path/path/to/resource服务器上的资源路径
querykey=value&name=test查询参数,以键值对形式传递
fragmentsection片段标识,用于定位页面内部锚点

需要特别说明的是,fragment 在 HTTP 请求中不会被发送到服务器,它只在客户端用于定位页面位置。这一点面试中经常被问到,很多人会误以为 fragment 也会随着请求发出。

2.3 浏览器对 URL 的规范化与编码

URL 默认只允许 ASCII 字符。当你输入包含中文或其他非 ASCII 字符的 URL 时,浏览器会进行编码处理:

  • 域名部分使用 Punycode 编码。例如「淘宝.com」会被转换成 xn--czr0bb03b.com 这样的形式,再交给 DNS 解析。

  • 路径和查询参数部分使用 百分号编码(Percent-Encoding)。例如中文「你好」会被编码成 %E4%BD%A0%E5%A5%BD,空格被编码成 %20 或 +。

这一步的价值在于:它回答了「中文域名到底是怎么被访问的」这类冷门但能体现知识深度的问题。

2.4 强制 HTTPS 与 HSTS

如果你输入的是 http://example.com,但该站点配置了 HSTS(HTTP Strict Transport Security),浏览器会在本地直接改写为 https://,根本不发 HTTP 请求。HSTS 通过响应头 Strict-Transport-Security 生效,例如:

text

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

它解决的核心问题是:避免每一次都先走不安全的 HTTP 再被 301 跳转到 HTTPS,从而减少中间人攻击的窗口期。这道追问能体现你对「安全细节」的敏感度。

2.5 浏览器多进程架构下的导航流程

现代浏览器(以 Chrome 为例)采用多进程架构。一次地址栏导航会涉及以下几个进程的协作:

  • 浏览器主进程:负责地址栏输入、UI 展示、进程调度,发起导航请求。

  • 渲染进程:负责页面的解析和渲染。导航发生时,可能会新开一个渲染进程,也可能复用旧的。

  • 网络进程:负责实际的网络请求,包括 DNS 解析、TCP 连接、TLS 握手、HTTP 请求等,是这条链路中的「执行者」。

  • GPU 进程:负责页面的绘制和合成。

完整的进程协作大致是:浏览器主进程把导航请求交给网络进程,网络进程负责完成整条网络链路,拿到响应后再把数据通过 IPC 交给渲染进程渲染。如果你能在回答中明确提出「网络进程」这个概念,就比只说「浏览器发请求」的候选人高出一个层次。

2.6 导航开始前的钩子:beforeunload

如果当前页面还有未提交的表单内容或正在播放的视频,浏览器会在离开当前页面前触发 beforeunload 事件,询问用户是否确认离开。这个事件可以阻止导航继续进行。

这是一个小但实用的细节:它说明「网络请求」不是从用户敲回车的那一刻就必然发起的,浏览器有一个「允许离开」的确认阶段。

2.7 预解析与预连接

为了加速导航,浏览器还有一个「预热」机制。当用户还在输入或者鼠标悬停在链接上时,浏览器就可能预测用户接下来要访问哪个域名,提前做 DNS 预解析(DNS Prefetch) 或 TCP 预连接(Preconnect):

html

<link rel="dns-prefetch" href="//example.com">
<link rel="preconnect" href="//api.example.com">

这样当真正需要请求时,DNS 和 TCP 可能已经提前就绪。这个知识点属于「性能优化与浏览器机制」的交集,在回答中作为延伸出来讲会很加分。

三、DNS 解析:一个域名是如何变成 IP 的

如果面试官只能追问一个环节,他大概率会选择 DNS。因为 DNS 是整条链路中最「看不见摸不着」但又最「卡时间」的部分,也是大多数候选人只懂皮毛的部分。

3.1 为什么需要 DNS

网络层最终是靠 IP 地址通信的,但 IP 地址对人不友好。DNS(Domain Name System)的核心作用就是提供「域名到 IP」的映射,让我们可以用有意义的域名访问服务,而不必记住一串数字。

但 DNS 的意义远不止「查个 IP」。站在工程视角,它还承担了:

  • 负载均衡:同一个域名可以返回不同 IP,实现流量分发。

  • CDN 调度:根据用户地理位置返回最近的节点 IP。

  • 故障转移:某个机房挂了,可以摘掉对应 IP,把流量切到其他机房。

  • 服务发现:在微服务体系中,服务名到实例地址的映射也依赖类似 DNS 的机制。

理解这一点,你就能明白为什么大厂对 DNS 环节极其重视。

3.2 DNS 查询的完整链路

浏览器拿到域名后,并不会直接去问「根域名服务器」,而是先走一层层缓存。DNS 查询的完整顺序如下:

  1. 浏览器 DNS 缓存:浏览器自身会缓存最近查询过的域名,通常缓存时间很短(Chrome 大约 1 分钟)。

  2. 操作系统缓存:如果浏览器缓存未命中,会查询操作系统缓存。在 Windows 上是 DNS Client 服务,在 Linux 上通常没有系统级缓存,而是由 /etc/resolv.conf 指定的解析器直接查询。

  3. hosts 文件:操作系统在查询 DNS 之前,会先检查本机 hosts 文件是否有该域名的映射。这也是本地开发和域名劫持的常用手段。

  4. 路由器缓存:家庭或公司网络的路由器一般也有自己的 DNS 缓存。

  5. 本地 DNS 服务器(LDNS):通常由 ISP(互联网服务提供商)提供,如电信、联通、移动的 DNS 服务器。如果以上缓存都未命中,请求会发给 LDNS。

如果 LDNS 也没有缓存,它就会代替客户端进行递归查询,从根域名服务器开始一级一级查下去。

3.3 递归查询与迭代查询

这是 DNS 面试题的核心概念,一定要分清楚:

  • 递归查询:客户端把查询任务完全交给 LDNS,LDNS 负责查到底,最后只把结果返回给客户端。客户端和 LDNS 之间是递归关系。

  • 迭代查询:LDNS 逐级向上查询时,根域名服务器、顶级域名服务器、权威域名服务器都不替它查到底,而是告诉它「下一步去哪里问」。LDNS 和上级服务器之间是迭代关系。

一个完整的过程是这样的:

text

客户端 --递归查询--> 本地DNS服务器
本地DNS服务器 --迭代查询--> 根域名服务器
根域名服务器:"我不知道 www.example.com 的 IP,但我知道 com 的权威服务器在哪"
本地DNS服务器 --迭代查询--> .com 顶级域名服务器
.com 顶级域名服务器:"我不知道 www 的 IP,但我知道 example.com 的权威服务器在哪"
本地DNS服务器 --迭代查询--> example.com 权威域名服务器
权威域名服务器:"www.example.com 的 IP 是 93.184.216.34"

面试官如果问「递归和迭代有什么区别」,核心区别就是:递归是别人替你查到底,迭代是别人只给你指路,你自己接着问。

3.4 DNS 的分层结构

域名系统是一个树形层级结构,从右到左层级依次升高:

text

根域(.,隐含不写)
└── 顶级域(com、cn、org、net...)
    └── 二级域(example.com、baidu.com...)
        └── 子域(www.example.com、api.example.com...)

需要记住的是:全球有 13 组根域名服务器(从 a.root-servers.net 到 m.root-servers.net),这 13 组不是 13 台物理机器,而是 13 个 IP 集群,通过 Anycast 技术分布在全球各地。顶级域名服务器负责 com、cn、org 等顶级域,权威域名服务器负责具体某个域名(如 example.com)的记录。

3.5 DNS 报文与常见记录类型

DNS 查询和响应使用同一个报文格式,主要字段包括:

  • Transaction ID:事务 ID,用于匹配请求和响应。

  • Flags:标志位,标记是查询还是响应、是否有错误等。

  • Questions:查询的域名、类型和类别。

  • Answers:应答记录,即查询结果。

常见的 DNS 记录类型:

记录类型作用示例
A将域名指向 IPv4 地址example.com → 93.184.216.34
AAAA将域名指向 IPv6 地址example.com → 2606:2800:220:1:248:1893:25c8:1946
CNAME域名别名,指向另一个域名www.example.com → example.com
NS指定该域名的权威 DNS 服务器example.com 的 NS 记录
MX邮件交换记录用于邮件投递
TXT文本记录,常用于域名验证、SPFDNS 验证记录

面试中常问的一个点是:CNAME 和 A 记录的区别。A 记录直接把域名解析到 IP,CNAME 则是把域名指向另一个域名,最终还是要通过别名域名的 A 记录才能拿到 IP。所以 CNAME 会导致额外的一次查询。

3.6 一个容易被忽略的点:CNAME 对 CDN 的意义

CDN(内容分发网络)的核心是让用户访问离他最近的节点。实现方式通常是:

  1. 让你的主域名(如 www.example.com)CNAME 到 CDN 厂商提供的域名(如 example.cdn.com)。

  2. CDN 厂商在自己的权威 DNS 服务器上,根据请求来源的 LDNS IP 判断用户地理位置,返回就近节点的 A 记录。

这种「根据来源 IP 做智能调度」的机制被称为 GSLB(全局负载均衡)。这就是为什么同一个域名,在北京解析出的 IP 和在深圳解析出的 IP 可能完全不同。

3.7 DNS 的安全问题:劫持与污染

既然 DNS 是「问路」,那就存在「有人给你指错路」的风险:

  • DNS 劫持:攻击者篡改 DNS 响应,把用户导向钓鱼网站。常见的劫持发生在路由器、运营商或本地 hosts 文件层面。

  • DNS 污染:在请求到达权威服务器之前,攻击者抢先返回伪造的响应。因为 DNS 查询默认走 UDP 且明文传输,攻击者可以在真实响应到达前,抢先注入一个伪造的 IP 响应包,让客户端拿到错误结果。

对应的防护手段主要有 DNSSEC、DoT(DNS over TLS) 和 DoH(DNS over HTTPS)。DNSSEC 通过数字签名保证响应来源可信,DoT 和 DoH 则通过加密通道防止查询内容被篡改或窃听。这里还有一个常见的追问:DNS 为什么默认走 UDP?答案是它追求低延迟和高吞吐,单次查询报文通常很小,UDP 一次往返即可完成;但 UDP 报文长度受限,遇到大响应时会退化为 TCP 53 端口。

四、TCP 连接:从三次握手到可靠传输

拿到服务器 IP 之后,浏览器要开始建立真正的连接。如果你访问的是 HTTP 站点,下一步就是 TCP 三次握手;如果是 HTTPS 站点,则先完成 TCP 握手,再进行 TLS 握手。这一章我们先把 TCP 的底子打牢。

4.1 为什么 TCP 需要三次握手

三次握手的目的可以浓缩成一句话:双方都要确认自己的发送能力和对方的接收能力都正常。第一次握手确认了客户端的发送能力,第二次握手确认了服务端的发送能力和客户端的接收能力,第三次握手才最终确认了服务端的接收能力。

如果用两次握手,服务端在发出第二次握手包后,无法知道客户端是否真的收到了自己的响应,也就无法确认双方序列号是否同步成功。更严重的是,网络中存在延迟的历史连接请求,如果服务端收到一个已经过期的 SYN 就立刻建立连接,会造成资源浪费。三次握手通过让客户端最后确认一次,能够有效减少无效连接。

4.2 三次握手的完整过程

三次握手的交互流程如下:

  1. 第一次握手:客户端发送 SYN 包,随机生成初始序列号 seq=x,进入 SYN_SENT 状态。此时客户端明确自己可以发送数据。

  2. 第二次握手:服务端收到 SYN 后回复 SYN+ACK 包,确认号 ack=x+1,并生成自己的初始序列号 seq=y,进入 SYN_RCVD 状态,同时把该连接放入半连接队列。

  3. 第三次握手:客户端收到 SYN+ACK 后回复 ACK 包,确认号 ack=y+1,进入 ESTABLISHED 状态。服务端收到 ACK 后,将连接从半连接队列移入全连接队列,也进入 ESTABLISHED 状态。

可以用下面的时序图表示:

text

客户端                          服务端
  | ---- SYN, seq=x -----------> |
  | <--- SYN+ACK, seq=y, ack=x+1 -|
  | ---- ACK, ack=y+1 ---------> |
  | 连接建立                     |

这里隐藏两个高频追问。第一,初始序列号为什么是随机的:如果序列号固定,攻击者容易预测下一个连接的序列号,进而伪造报文劫持会话。第二,SYN 队列和 SYN Flood 攻击:服务端收到 SYN 而未收到第三次握手前,连接会一直占用半连接队列。攻击者大量发送 SYN 而不完成握手,就会耗尽队列资源,这就是 SYN Flood。常见防御手段包括 SYN Cookie、限制半连接数量和流量清洗。

4.3 四次挥手与 TIME_WAIT

连接建立要三次握手,断开却要四次挥手,原因是 TCP 是全双工的,两个方向要分别关闭。四次挥手的过程是:

  1. 主动关闭方发送 FIN,表示自己不再发送数据。

  2. 被动关闭方回复 ACK,表示确认收到对方的关闭请求。

  3. 被动关闭方处理完剩余数据后,也发送 FIN。

  4. 主动关闭方回复 ACK,连接彻底关闭。

主动关闭方在发送最后一个 ACK 后会进入 TIME_WAIT 状态,等待 2MSL 时间。这不是 bug,而是为了确保最后一个 ACK 丢失时,对方能重发 FIN,同时让旧连接的迟到报文自然消失,避免影响新连接。面试中问「服务器上有大量 TIME_WAIT 怎么办」,可以回答调整内核参数(如 tcp_tw_reuse、缩短 TIME_WAIT 时间)或从架构上让客户端主动关闭连接。

4.4 可靠传输:序列号、确认应答与超时重传

TCP 的可靠性建立在三个机制上:

  • 序列号与确认应答:每个字节数据都有编号,接收方通过 ACK 告诉发送方「期待的下一个字节序号」,保证数据有序且不丢失。

  • 超时重传:发送方每发送一段数据就启动定时器,超时未收到确认就重传。超时时间会通过 RTT 动态估算,即 RTO。

  • 快速重传:如果接收方连续收到三个相同 ACK(说明后续数据包乱序或丢失),发送方不必等超时就立即重传缺失的报文。

此外还有滑动窗口机制,它让发送方可以连续发送多个报文而不必等每个 ACK,从而提升吞吐。窗口大小由接收方的缓冲区决定,接收方通过 ACK 报文中的 Window 字段动态告知发送方。

4.5 拥塞控制:慢启动与快恢复

可靠传输解决的是「不丢」,拥塞控制解决的是「不把网络压垮」。TCP 通过四个算法动态调整发送窗口:

  • 慢启动:连接刚建立时窗口很小,每收到一个 ACK 就把拥塞窗口翻倍,指数增长到慢启动阈值。

  • 拥塞避免:窗口超过阈值后改为线性增长,每个 RTT 只增加一个报文段,避免过快占满带宽。

  • 快重传:收到三个重复 ACK 时立即重传,而不是等待超时。

  • 快恢复:快重传后不回到慢启动,而是把阈值减半后直接进入拥塞避免,快速恢复传输速率。

面试时如果能结合「为什么网速时快时慢」「为什么弱网下上传很吃力」来解释拥塞控制,会比只背名词更有说服力。

五、TLS 握手:HTTPS 的安全底座

现代网站几乎都运行在 HTTPS 上,所以「URL 输入到返回请求」这条链路里,TLS 握手是绕不开的一环。它不仅负责加密,还负责身份认证和完整性校验。

5.1 为什么需要 TLS

如果只有 TCP,数据是明文传输的,中间人可以轻松窃听、篡改甚至伪装。TLS(Transport Layer Security)在 TCP 之上提供三个核心能力:

  • 机密性:通过对称加密保证通信内容不被第三方读取。

  • 完整性:通过消息摘要或 MAC 保证内容没有被篡改。

  • 身份认证:通过数字证书验证服务器身份,防止中间人伪装。

5.2 TLS 1.2 的握手过程

TLS 1.2 的完整握手需要两个 RTT,大致过程如下:

  1. ClientHello:客户端发送支持的 TLS 版本、加密套件、随机数。

  2. ServerHello:服务端选定加密套件,返回自己的随机数和数字证书。

  3. 证书验证:客户端验证证书链是否可信,确认服务端身份。

  4. 密钥协商:双方根据密钥交换算法协商出共享的会话密钥。传统 RSA 模式由客户端生成预主密钥并用服务端公钥加密;现代 ECDHE 模式则通过椭圆曲线临时密钥对实现前向保密。

  5. 完成确认:双方发送 Finished 消息,验证握手和加密通道是否正常。

面试中常问「RSA 和 ECDHE 的区别」,核心答案有两点:ECDHE 支持前向保密,即使服务端私钥泄露,历史会话也无法被解密;而 RSA 模式下会话密钥由客户端生成并用服务端公钥加密,一旦服务端私钥泄露,历史流量都能被解开。

5.3 TLS 1.3 的改进

TLS 1.3 做了大幅简化,握手缩短到 1 RTT,主要有三个变化:

  • 删除不安全的算法:移除了 RSA 密钥交换、SHA-1、3DES 等过时方案,只保留安全性更高的算法。

  • 握手更快:密钥协商提前到 ClientHello 阶段,减少一个往返。

  • 0-RTT 模式:在会话恢复场景下,客户端可以在首次往返中就携带加密数据,进一步压低延迟。

5.4 会话恢复与性能优化

TLS 握手本身有一定成本,生产环境中常用两种方式复用会话参数:

  • Session ID:服务端缓存会话参数,客户端下次带上 Session ID 即可快速恢复。

  • Session Ticket:服务端把会话参数加密成 Ticket 交给客户端保存,恢复时无需服务端缓存,适合多节点架构。

如果能继续聊到「HTTPS 虽然加密,但 SNI 和证书握手阶段仍是明文」这个点,面试官会认为你确实理解 TLS 的实际约束。

六、HTTP 请求:报文、版本与状态

TCP 或 TLS 连接建立之后,浏览器终于可以发送真正的 HTTP 请求了。这一步看似简单,但报文结构、Cookie、版本差异和状态码都是面试重点。

6.1 HTTP 请求报文结构

一个典型的 HTTP/1.1 请求报文由请求行、请求头和可选的请求体组成:

text

GET /path/to/resource?key=value HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html,application/xhtml+xml
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: session_id=abc123

请求行包含方法、目标路径、协议版本。请求头中 Host 用于区分同一 IP 上的多个虚拟主机,Accept-Encoding 声明客户端支持的内容压缩方式,Cookie 携带客户端状态。

6.2 常用请求方法与幂等性

最常用的方法有 GET、POST、PUT、DELETE,其中前两个在面试中出现频率最高:

  • GET:获取资源,参数通常放在 URL 中,是幂等的,可被缓存。

  • POST:提交数据,参数放在请求体中,不是幂等的,一般不缓存。

这里要强调「幂等性」:GET、PUT、DELETE 是幂等的,重复调用不会产生额外副作用;POST 不是幂等的,重复提交可能创建多条记录。面试中「GET 和 POST 的区别」如果只回答「GET 在 URL 带参、POST 在 Body 带参」,实在太浅;再加上幂等性、缓存、语义和安全性差异,才算完整。

6.3 Cookie 与 Session

HTTP 本身是无状态的,Cookie 就是用来保存状态的方案。服务端通过 Set-Cookie 响应头把标识写进浏览器,浏览器后续请求自动携带回来。常见的属性包括:

  • HttpOnly:禁止 JS 读取,降低 XSS 攻击风险。

  • Secure:只在 HTTPS 下传输。

  • SameSite:限制跨站请求时是否携带,用于减轻 CSRF 攻击。

如果继续追问分布式下 Session 怎么共享,可以回答:粘性会话、独立 Session 服务、Redis 集中存储,以及更现代的 JWT Token 方案。

6.4 HTTP/1.1、HTTP/2 与 HTTP/3

不同版本的差异是面试高频点:

  • HTTP/1.1:默认长连接,但同一连接上的请求是串行的,浏览器通过开多个连接缓解队头阻塞。

  • HTTP/2:引入多路复用,所有请求可在一个 TCP 连接上并行;同时支持头部压缩、二进制分帧和服务端推送。但底层仍是 TCP,丢包仍然会导致整个连接上的流受影响。

  • HTTP/3:底层从 TCP 换成基于 UDP 的 QUIC,实现无队头阻塞、连接迁移和更快的握手,更适合弱网和移动场景。

6.5 状态码速记

掌握状态码的区间含义就足够应对大多数追问:

  • 1xx:信息性,如 101 协议切换。

  • 2xx:成功,如 200 请求成功、204 无内容。

  • 3xx:重定向,如 301 永久重定向、302 临时重定向、304 缓存未过期。

  • 4xx:客户端错误,如 400 参数错误、401 未认证、403 无权限、404 资源不存在。

  • 5xx:服务端错误,如 500 服务器内部错误、502 网关错误、503 服务不可用、504 网关超时。

304 尤其值得展开:当浏览器携带缓存标识去访问时,服务端如果判断资源没变化,就返回 304 并不带回响应体,浏览器继续使用本地缓存,从而节省带宽。

七、负载均衡与反向代理

你访问的 www 域名后面,通常站着一整个集群,而不是单台服务器。请求从公网进来后,第一站往往是负载均衡器或反向代理。

7.1 为什么需要负载均衡

单台服务器的性能和可用性都有上限。负载均衡的核心价值有三个:

  • 横向扩展:把流量分摊到多台机器,提升整体吞吐。

  • 高可用:某台机器故障时自动摘除,不影响整体服务。

  • 灵活运维:发布时可以先摘掉部分节点做灰度或滚动更新,减少停机。

7.2 常见的负载均衡算法

  • 轮询:依次分配,实现简单,但不考虑机器负载差异。

  • 加权轮询:为性能更高的机器配置更高权重。

  • 随机:随机选择一台,配合权重效果类似加权轮询。

  • 最少连接数:把请求分配给当前连接数最少的机器,适合长连接场景。

  • 一致性哈希:根据请求特征(如用户 ID、IP)映射到固定节点,适合需要会话黏着或缓存命中的场景。

7.3 反向代理与网关

反向代理站在服务端一侧,接收公网请求并转发到内部服务器。除了负载均衡,它还承担:

  • SSL 卸载:由代理统一处理 HTTPS 加密解密,内网流量保持明文,降低后端压力。

  • 安全防护:隐藏内部服务器拓扑,过滤恶意请求。

  • 路由与灰度:按路径或 Header 把请求分流到不同服务版本。

常见实现有 Nginx、OpenResty、Envoy、HAProxy,以及云厂商提供的负载均衡服务。微服务架构中,还会在网关层叠加鉴权、限流、熔断、链路追踪等能力。

八、后端服务处理请求

请求到达后端后,会经历一系列处理,这一部分也是面试官最容易从「网络」切换到「后端工程」的地方。

8.1 从网关到应用服务

典型链路是:负载均衡 → API 网关 → 应用服务。网关负责统一的鉴权、限流、路由、日志,应用服务负责真正的业务逻辑。服务之间通过 RPC 或 HTTP 调用,也可能通过消息队列解耦。

8.2 应用层处理

应用服务收到请求后,通常按分层架构处理:

  • Controller 层:解析参数、校验、调用 Service。

  • Service 层:业务逻辑、事务边界、跨服务调用。

  • Repository 层:数据访问,可能走缓存、数据库、搜索引擎。

8.3 数据访问与缓存

数据访问是链路上最慢的一环,所以通常会叠加多级缓存:

  • 本地缓存:Caffeine、Guava Cache,访问速度最快。

  • 分布式缓存:Redis、Memcached,跨节点共享。

  • 数据库:MySQL、PostgreSQL,最终一致性的落点。

如果继续追问缓存穿透、击穿、雪崩,可以结合具体业务场景说明防御方案。如果能提到「缓存与数据库的双写一致性」,说明你有实际工程经验。

8.4 事务与一致性

单库场景用本地事务即可,跨库场景需要引入分布式事务或最终一致性方案:

  • 强一致:2PC/XA,性能差但一致性最强。

  • 最终一致:TCC、Saga、本地消息表、事务消息、最大努力通知。

面试时如果能说出「业务上大多允许最终一致,所以实际项目中优先选柔性事务」这样的取舍,会非常加分。

九、响应返回与浏览器渲染

服务端处理完成后,响应会沿着原链路返回客户端,然后进入浏览器渲染阶段。

9.1 响应报文结构

响应报文包括状态行、响应头、响应体:

text

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 12345
Cache-Control: max-age=3600
Set-Cookie: session_id=abc123; HttpOnly; Secure

<html>...</html>

Content-Type 告诉浏览器如何解析响应体,Cache-Control 决定缓存策略,Content-Encoding 表示压缩方式。

9.2 浏览器渲染流程

浏览器拿到 HTML 后,会经历以下阶段:

  1. 解析 HTML:构建 DOM 树。

  2. 解析 CSS:构建 CSSOM 树。

  3. 合并渲染树:DOM + CSSOM 合并成 Render Tree。

  4. 布局:计算每个节点的位置和大小。

  5. 绘制:把节点绘制到图层。

  6. 合成:把图层合成为最终页面。

如果涉及 JS,还会遇到 JS 阻塞解析、异步加载、DOMContentLoaded 和 load 事件的区别等高频话题。

9.3 关键渲染路径优化

优化首屏渲染的常见手段包括:

  • 减少关键资源数量:内联关键 CSS,异步加载非关键 JS。

  • 使用 preload / prefetch:提前加载关键资源,预取后续资源。

  • 开启 HTTP/2、HTTP/3:减少连接数,充分利用多路复用。

  • 合理使用 CDN:静态资源就近分发。

  • 启用 Gzip / Brotli 压缩:减少传输体积。

十、面试回答模板与高频追问

10.1 标准回答结构

如果把整条链路浓缩成一段回答,可以按以下五层递进:

  1. 浏览器处理:判断输入类型、URL 规范化、HSTS 改写、进程协作。

  2. DNS 解析:缓存 → hosts → LDNS → 递归/迭代查询 → 拿到 IP。

  3. 建立连接:TCP 三次握手(HTTPS 再加 TLS 握手),协商加密通道。

  4. 发送请求:HTTP 报文、Cookie、请求方法、连接复用。

  5. 服务端处理与响应:负载均衡、网关、应用服务、缓存/数据库,返回响应后浏览器渲染。

每一层都能再往下挖三层,这就是深度。

10.2 高频追问清单

  • DNS 递归和迭代有什么区别?

  • 为什么 TCP 是三次握手不是两次?

  • TIME_WAIT 为什么需要 2MSL?

  • TLS 1.2 和 TLS 1.3 握手有什么区别?

  • HTTP/2 相比 HTTP/1.1 有什么改进?

  • 304 状态码如何触发?

  • 反向代理和正向代理的区别?

  • 分布式 Session 怎么共享?

  • 缓存穿透、击穿、雪崩怎么处理?

  • 浏览器输入 URL 后为什么有时候不是发 HTTP 请求?

10.3 最后总结

这道题真正的难点,不在于背出一长串流程,而在于:

  • 结构化表达:把链路拆成清晰的阶段,每阶段先讲目的、再讲过程、最后讲异常。

  • 工程视角:不只是理论,还要讲缓存、压缩、CDN、限流、灰度。

  • 深度下钻:每个环节都能追三层,从 API 到协议再到操作系统。

  • 闭环思维:从用户输入开始,到浏览器渲染结束,回答形成闭环。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐