网络题是前端面试的底层能力题。优秀回答要能从协议特性落到页面加载、接口稳定性和安全。

HTTP

HTTP/1.1

知识点讲解

HTTP/1.1 支持长连接、管线化、缓存控制和 Host 头。它的问题是队头阻塞:同一个连接上的请求响应必须按顺序返回,所以浏览器通常会为同一域名开多个连接。

面试常问

问:HTTP/1.1 有什么性能问题?

答:请求头重复、连接数量有限、队头阻塞明显。优化手段包括连接复用、资源合并、缓存、域名分片,但这些在 HTTP/2 时代不一定仍然适合。

HTTP/2 与 HTTP/3

知识点讲解

HTTP/2 使用二进制分帧、多路复用、头部压缩和服务端推送。它解决了 HTTP 层队头阻塞,但 TCP 层丢包仍会影响整个连接。HTTP/3 基于 QUIC 和 UDP,减少握手成本,并改善 TCP 层队头阻塞。

面试常问

问:HTTP/2 为什么还会有队头阻塞?

答:HTTP/2 的多个流复用在同一个 TCP 连接上。TCP 必须保证字节流有序,一旦某个包丢失,后续数据即使到了也要等待重传,所以会出现 TCP 层队头阻塞。

TCP、UDP 与 QUIC

TCP

知识点讲解

TCP 面向连接,提供可靠、有序、拥塞控制的数据传输。三次握手建立连接,四次挥手释放连接。可靠性来自序列号、确认应答、重传、滑动窗口和拥塞控制。

面试常问

问:为什么 TCP 建连需要三次握手?

答:三次握手能确认双方收发能力都正常,并同步初始序列号。两次握手无法可靠确认客户端接收能力,也可能造成历史连接请求导致的资源浪费。

UDP 与 QUIC

知识点讲解

UDP 无连接、不保证可靠和有序,但开销小、延迟低。QUIC 在 UDP 之上实现可靠传输、拥塞控制、连接迁移和 TLS 加密,服务于 HTTP/3。

面试常问

问:HTTP/3 为什么用 UDP?

答:不是因为 UDP 本身可靠,而是 QUIC 在用户态基于 UDP 实现了可靠传输和多路复用。这样可以绕开 TCP 的一些限制,减少握手延迟,并支持连接迁移。

HTTPS 与 TLS

TLS 握手

知识点讲解

HTTPS = HTTP + TLS。TLS 握手会协商加密套件、验证证书、生成会话密钥。传输数据通常使用对称加密,证书和密钥协商阶段使用非对称加密能力。

面试常问

问:HTTPS 为什么既用非对称加密又用对称加密?

答:非对称加密适合身份验证和密钥协商,但性能较差;对称加密性能好,适合大量数据传输。HTTPS 结合两者,既保证安全又兼顾性能。

证书与中间人攻击

知识点讲解

证书由 CA 签发,浏览器通过证书链验证服务端身份。如果攻击者伪造证书但无法被可信 CA 链验证,浏览器会拦截。证书还要匹配域名和有效期。

面试常问

问:HTTPS 一定安全吗?

答:它能保证传输加密、身份验证和完整性,但不代表业务绝对安全。前端仍要防 XSS、CSRF,后端仍要鉴权、限流、校验输入。

DNS、CDN 与缓存

DNS

知识点讲解

DNS 把域名解析成 IP。解析路径通常涉及浏览器缓存、系统缓存、递归解析器、根域名服务器、顶级域服务器、权威域服务器。DNS 解析耗时会影响首屏。

面试常问

问:DNS 解析怎么优化?

答:减少域名数量,使用 DNS 缓存,合理设置 TTL,关键域名可以用 dns-prefetch,并通过 CDN 就近解析。

CDN

知识点讲解

CDN 通过边缘节点缓存静态资源,让用户从更近的节点获取内容。它能降低延迟、减轻源站压力、提升可用性。

面试常问

问:CDN 缓存更新不及时怎么办?

答:静态资源使用内容哈希文件名,资源变更后 URL 变化;HTML 设置较短缓存或协商缓存;必要时通过 CDN 刷新接口主动清缓存。

底层追问与代码示例

TCP 粘包与应用层协议

知识点讲解

TCP 是字节流协议,没有消息边界。发送端写了两次,接收端可能一次读到,也可能分多次读到,这就是常说的粘包/拆包。解决方案在应用层定义边界:固定长度、分隔符、长度前缀。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 长度前缀协议示意:前 4 字节表示 body 长度
function encodeMessage(payload) {
const body = Buffer.from(JSON.stringify(payload))
const header = Buffer.alloc(4)
header.writeUInt32BE(body.length)
return Buffer.concat([header, body])
}

function decodeMessages(buffer) {
const messages = []
let offset = 0

while (offset + 4 <= buffer.length) {
const length = buffer.readUInt32BE(offset)
if (offset + 4 + length > buffer.length) break
const body = buffer.slice(offset + 4, offset + 4 + length)
messages.push(JSON.parse(body.toString()))
offset += 4 + length
}

return { messages, rest: buffer.slice(offset) }
}

面试常问

问:HTTP 为什么不需要你手动处理粘包?

答:因为 HTTP 自己已经定义了消息格式,比如请求行、头部、空行、Content-LengthTransfer-Encoding: chunked,应用层协议已经解决了消息边界。

HTTP 缓存请求头示例

知识点讲解

缓存题要能把请求和响应头串起来。

1
2
3
HTTP/1.1 200 OK
Cache-Control: public, max-age=31536000, immutable
ETag: "main.2e8ab.js"

强缓存过期后,浏览器可能发起协商请求:

1
2
GET /main.2e8ab.js HTTP/1.1
If-None-Match: "main.2e8ab.js"

服务器确认未变化:

1
2
HTTP/1.1 304 Not Modified
ETag: "main.2e8ab.js"

面试常问

问:为什么 304 也算一次请求?

答:304 是协商缓存,浏览器仍然请求了服务器,只是服务器不返回 body。它节省带宽,但不省 RTT。

跨域预检完整例子

知识点讲解

带自定义头或非简单方法时,浏览器会先发 OPTIONS。

1
2
3
4
OPTIONS /api/user HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: content-type,x-token

服务端允许:

1
2
3
4
5
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: content-type,x-token
Access-Control-Max-Age: 86400

面试常问

问:为什么带 cookie 的 CORS 不能用 *

答:带凭证请求必须设置具体 Access-Control-Allow-Origin,并且需要 Access-Control-Allow-Credentials: true* 会被浏览器拒绝。