计算机网络热门面试题
使用说明
本篇共 54 道题。
网络题适合按“应用层请求—传输—名称解析—安全—架构”回答。重点是解释为什么这样设计,以及它对前端和服务端的影响。
Q1: OSI 七层和 TCP/IP 模型有什么价值?
答案:
它们把通信职责分层,便于协议演进和故障定位。实际互联网常用 TCP/IP 模型理解:应用层、传输层、网络层和链路层。
面试中不要只背层数,可举例:HTTP 在应用层,TCP/UDP 在传输层,IP 负责跨网络寻址,链路层负责本地传输。
- 分层模型的价值是明确职责和排障边界:应用问题先看 HTTP/DNS,连通问题再下沉到传输层和网络层。
- OSI 更适合概念教学,工程上通常按 TCP/IP 四层理解;一次请求会逐层封装,接收端再反向解封装。
Q2: HTTP 是什么?它有哪些核心特点?
答案:
HTTP 是请求—响应式应用层协议,消息由方法、目标、头和可选正文组成。协议本身无业务会话状态,状态通常通过 Cookie、Token 和服务端数据建立。
连接是否复用、并发和加密由具体 HTTP 版本和传输层决定,不能简单把 HTTP 等同于“一次请求一次 TCP”。
Q3: GET 和 POST 有什么区别?
答案:
核心区别是 HTTP 方法语义,不是“一个安全、一个不安全”:
- GET 用于读取资源,按规范应是 safe、幂等,参数常放在 URL 中,响应更容易被缓存、预取和分享。
- POST 用于把数据提交给资源处理,常用于创建或执行命令,默认不保证幂等,正文格式由 Content-Type 决定。
- URL 和请求正文都可能被日志、代理或监控记录,敏感信息都需要 HTTPS 和最小化暴露。
- GET 也可以有请求正文,但语义和中间设施支持不统一,业务接口不应依赖。
- POST 也能通过明确缓存头被缓存,但生态默认行为与 GET 不同。
接口选方法应看业务语义、幂等性和缓存需求,不应按参数长度简单决定。
Q4: 什么是幂等?
答案:
幂等性指同一操作执行多次,结果与执行一次相同。
| 方法 | 幂等 | 原因 |
|---|---|---|
| GET | ✅ | 只读操作 |
| PUT | ✅ | 全量替换,结果相同 |
| DELETE | ✅ | 删除后再删除,资源仍不存在 |
| POST | ❌ | 每次创建新资源 |
| PATCH | ❌ | 可能依赖当前状态 |
Q5: 常见 HTTP 状态码怎么回答?
答案:
面试时按类别和业务含义回答,比机械背数字更清晰:
- 2xx:
200 OK成功;201 Created创建成功并可返回 Location;204 No Content成功但无响应正文。 - 3xx:
301/308永久重定向,302/307临时重定向;307/308 明确保留原请求方法。 - 4xx:
400请求格式错误,401未认证,403已识别但无权限,404资源不存在,409状态冲突,422内容语义校验失败,429限流。 - 5xx:
500未知服务端错误,502网关拿到无效上游响应,503暂不可用,504网关等待上游超时。
状态码要与重试、缓存和错误体协议一致,不能所有失败都返回 200 再把错误藏在 JSON 字段中。
Q6: HTTP 缓存的整体流程是什么?
答案:
客户端先判断强缓存是否新鲜;过期后携带验证器请求服务端,资源未变返回 304,变化则返回新内容。
Cache-Control 是主策略,ETag 更精确,Vary 决定缓存键维度。共享缓存还要防止把用户私有响应缓存给别人。
- 浏览器先判断强缓存,命中就不发请求;过期后带 ETag/Last-Modified 发起条件请求,服务端可返回
304复用本地实体。 - 带指纹的静态资源适合长期 immutable 缓存,HTML 通常短缓存或协商缓存;涉及用户数据时还要正确设置
private和Vary。
Q7: HTTPS 比 HTTP 多了什么?
答案:
HTTPS 是 HTTP 运行在 TLS 安全通道上,提供传输加密、完整性和服务端身份认证,客户端证书场景还可双向认证。
它不能保证服务端业务无漏洞,也不能防止终端本身被攻击。证书、协议套件、HSTS 和密钥管理仍要正确配置。
- HTTPS 是 HTTP 运行在 TLS 之上,提供传输加密、完整性校验和服务器身份认证,防止链路被窃听或篡改。
- 它不能自动阻止 XSS、越权或恶意服务端;证书校验、HSTS、混合内容和私钥保护仍属于部署重点。
Q8: TLS 握手大致做了什么?
答案:
客户端与服务端协商协议参数,服务端发送证书证明身份,双方通过密钥交换得到会话密钥,之后用对称加密传输应用数据。
现代版本减少握手往返并支持会话恢复。前端性能上关注连接复用、证书链和网络 RTT,不必在口头回答中推导全部密码学报文。
- 客户端先验证证书链和域名,双方协商 TLS 版本、密码套件与密钥材料,再通过非对称机制建立共享会话密钥。
- 后续应用数据使用对称加密传输以兼顾性能;TLS 1.3 减少了往返次数,会话恢复还能进一步降低重复连接成本。
Q9: TCP 为什么需要三次握手?
答案:
双方需要确认彼此的发送和接收能力,并同步初始序列号。第三次确认让服务端知道客户端已收到自己的响应,避免把过期连接请求直接当成有效连接。
三次是建立双向可靠状态的最小常见交互,不只是“客户端、服务端各说一次”。
- 第一次握手同步双方收发序列号,第二次由服务端同时确认客户端序列号并发送自己的序列号,第三次客户端再确认。
- 两次不足以让服务端确认客户端已经收到自己的初始序列号,也更容易让历史重复连接占用资源;三次是可靠建立双向状态的最小过程。
Q10: TCP 为什么常见四次挥手?
答案:
TCP 是全双工,某一方关闭发送方向后,另一方可能还有数据没发完,因此两个方向的 FIN/ACK 通常分别处理。
主动关闭方进入 TIME_WAIT,等待旧报文过期并能重发最后确认,避免新连接受到历史报文干扰。
- TCP 是全双工的,两个方向要分别关闭:主动方发 FIN、对端 ACK;对端处理完剩余数据后再发 FIN,主动方最后 ACK。
- 主动关闭方进入 TIME_WAIT,用来保证最后 ACK 可重传并让旧报文过期。并非所有关闭都严格四个独立包,ACK 与 FIN 可以合并。
Q11: TCP 和 UDP 怎么选?
答案:
| 维度 | TCP | UDP |
|---|---|---|
| 连接 | 面向连接 | 无连接 |
| 可靠性 | 可靠(重传、确认) | 不可靠 |
| 顺序 | 保证有序 | 不保证 |
| 速度 | 较慢 | 较快 |
| 头部 | 20-60 字节 | 8 字节 |
| 流控/拥塞 | 有 | 无 |
| 传输方式 | 字节流 | 数据报 |
Q12: DNS 解析过程是什么?
答案:
- 浏览器缓存:检查浏览器 DNS 缓存
- 系统缓存:检查操作系统缓存
- hosts 文件:检查本地 hosts
- 本地 DNS:查询 ISP DNS 服务器
- 递归查询:
- 根 DNS(.)→ 返回顶级 DNS 地址
- 顶级 DNS(.com)→ 返回权威 DNS 地址
- 权威 DNS → 返回目标 IP
- 缓存结果:各级缓存,下次直接返回
Q13: HTTP/2 相比 HTTP/1.1 改进了什么?
答案:
| 改进 | 说明 |
|---|---|
| 多路复用 | 单连接并行请求,解决队头阻塞 |
| 二进制分帧 | 高效解析,减少错误 |
| 头部压缩 | HPACK 算法,减少传输量 |
| 服务器推送 | 主动推送资源 |
| 流优先级 | 重要资源优先传输 |
Q14: HTTP/3 和 QUIC 的价值是什么?
答案:
HTTP/3 运行在 QUIC 上,QUIC 基于 UDP 在用户态实现加密和可靠多路流。单个流丢包不会像 TCP 那样阻塞其他流,并支持更快建连和连接迁移。
它仍受网络、服务端和中间设备支持影响,应通过真实用户数据评估收益并保留回退。
Q15: CDN 的工作原理是什么?
答案:
- DNS 解析:域名 CNAME 到 CDN,智能 DNS 返回最近节点
- 就近访问:用户访问离自己最近的边缘节点
- 缓存命中:边缘节点有缓存直接返回
- 回源:无缓存时向源站获取,缓存后返回
Q16: 正向代理、反向代理和负载均衡有什么区别?
答案:
- 正向代理代表客户端访问外部服务,服务端通常只看到代理地址。常见于企业出口、隐私代理和开发网络。
- 反向代理代表服务端集群接收客户端请求,客户端只看到统一入口。它可做 TLS 终止、路由、缓存和安全防护。
- 负载均衡是一项流量分配能力,把请求分发给多个后端;它可以由反向代理、四层设备、云服务或客户端实现。
三者不是互斥产品:Nginx 作为反向代理时可以同时执行负载均衡。面试中应先说明“代理谁”,再说明工作层级、路由依据、健康检查和会话保持。
Q17: Cookie/Session 和 JWT 怎么选?
答案:
| 区别 | Cookie | Session |
|---|---|---|
| 存储位置 | 浏览器 | 服务器 |
| 安全性 | 低(可篡改) | 高 |
| 存储大小 | 4KB | 无限制 |
| 生命周期 | 可设置过期 | 默认会话级 |
| 服务器压力 | 无 | 占用资源 |
工作关系:Session 通常依赖 Cookie 存储 SessionId。
Q18: WebSocket、SSE 和轮询怎么选?
答案:
WebSocket 提供长连接双向消息,适合聊天和协作;SSE 基于 HTTP 单向服务端推送,自动重连、文本事件简单;轮询兼容最好但延迟和请求开销较高。
都要考虑鉴权、心跳、断线重连、消息顺序、背压和扩容,不能只看 API 是否简单。
Q19: HSTS 解决什么问题?有什么上线风险?
答案:
HSTS 通过 Strict-Transport-Security 告诉浏览器:在有效期内,该域名只能使用 HTTPS。后续即使用户输入 http://,浏览器也会在发请求前升级,降低 SSL Stripping 风险。
上线要点:
- 只在 HTTPS 响应中生效。
- 先用较短
max-age验证所有子域都支持 HTTPS,再考虑includeSubDomains。 preload需要满足预加载列表要求,撤销慢,不能把它当普通开关。- HSTS 不能修复证书错误,也不能替代安全 Cookie、CSP 和服务端安全。
Q20: TCP 是字节流意味着什么?应用层怎样处理消息边界?
答案:
TCP 只提供有序、可靠的字节序列,不保留发送方每次 send/write 的边界。一次写入可能被拆成多次读取,多次写入也可能一次读出,所谓“粘包/拆包”本质是应用层没有正确解析协议边界。
常见消息定界方式:
- 固定长度。
- 分隔符,例如文本协议的换行,但要处理转义和长度上限。
- 长度前缀,先读头部长度再读完整正文。
- 自描述协议,例如 HTTP 的 Content-Length、Chunked Coding 或帧格式。
接收端必须维护缓冲区并循环解析,同时限制最大消息长度,防止内存攻击。
Q21: 为什么 HTTP/2 下不建议继续做域名分片?
答案:
HTTP/1.1 时代域名分片用于绕过单域连接数限制;HTTP/2 在一条连接上多路复用大量 Stream,继续拆到多个域名会增加 DNS、TCP/TLS 握手、连接拥塞窗口和资源调度成本。
同一证书、解析地址和浏览器策略满足时还可能发生连接合并,但不能假设所有域名都会自动共用连接。优化应减少无意义域名和连接,同时按 CDN、权限、故障域和第三方边界合理拆分。
HTTP/2 仍有 TCP 层队头阻塞;网络收益应通过真实连接复用率、RTT 和用户数据验证,而不是把所有资源强行放到一个域名。
Q22: 浏览器如何验证 HTTPS 证书是否可信?
答案:
浏览器会验证服务端证书链能否连接到本地信任的根证书,并检查域名、有效期、签名、用途和关键扩展。服务端通常发送站点证书和中间证书,根证书一般已在客户端信任库中。
还要注意:
- 域名必须匹配 SAN,不能只看证书“有锁”。
- 缺少中间证书可能导致部分客户端验证失败。
- 撤销检查受 OCSP、CRL、Stapling 和浏览器策略影响。
- HSTS 可以减少降级和绕过机会,但不能修复错误证书。
证书验证确认的是连接对端身份和链路加密,不代表网站业务本身可信或没有 XSS。
Q23: MTU 和 MSS 分别是什么?为什么会影响传输?
答案:
MTU 是某条链路一次可承载的最大 IP 包大小;TCP MSS 是一个 TCP 段中应用数据的最大长度,通常根据接口 MTU 扣除 IP 和 TCP 头部得到,并可在握手时协商。
包超过路径可承载大小时,IPv4 可能分片,IPv6 主要依赖发送端根据 Path MTU 调整。若 ICMP 反馈被错误拦截,可能出现 Path MTU black hole:小请求正常,大响应或 TLS 数据却卡住。
工程上通常让 TCP 分段与 PMTUD 处理,不按应用消息手工切成“1500 字节”。隧道、VPN、容器网络会增加额外头部,排查特定网络超时要检查实际路径 MTU、MSS clamping 和 ICMP 策略。
Q24: RESTful API 的设计原则?
答案:
- 使用名词复数:
/users而非/user - HTTP 方法语义化:GET 查询、POST 创建、PUT 更新、DELETE 删除
- 正确的状态码:200 成功、201 创建、400 参数错误、401 未认证、404 不存在
- 无状态:每次请求包含所有必要信息
- 版本控制:
/api/v1/users - 统一响应格式:成功和错误都有一致的结构
Q25: 四层负载均衡和七层负载均衡有什么区别?
答案:
四层负载均衡主要根据 IP、端口和连接信息转发 TCP/UDP,协议开销低、通用性强,但不了解具体 HTTP 路径和 Header。
七层负载均衡理解 HTTP 等应用层协议,可以按 Host、Path、Header、Cookie 路由,并执行 TLS 终止、鉴权、限流和内容规则;代价是处理成本、配置复杂度和协议耦合更高。
实际架构常组合使用:四层入口承载大规模连接,七层网关做业务路由。选型还要看长连接、源地址保留、健康检查、可观测性和故障切换。
Q26: 什么是 Session Fixation?怎样防御?
答案:
Session Fixation 是攻击者先让受害者使用一个攻击者已知的 Session ID,等受害者登录后再复用该 ID 冒充受害者。问题不在于“Session 存服务器就安全”,而在于登录前后的会话身份没有轮换。
防御措施:
- 登录、提权、修改重要身份后重新生成 Session ID,并废弃旧会话。
- Session ID 必须高熵、只由服务端生成。
- Cookie 设置 Secure、HttpOnly、合适的 SameSite 和作用域。
- 设置空闲与绝对过期时间,支持服务端撤销。
- 防止 ID 通过 URL、日志和 Referer 泄漏。
Q27: JWT 的优缺点和常见误区是什么?
答案:
JWT 是 Token 的一种紧凑声明格式,常用签名保证内容未被篡改。优点是跨服务传递声明方便、验证可本地完成、标准生态成熟;代价是 Token 较大、撤销和权限实时变更更复杂,声明还可能过期或泄漏。
常见误区:
- 签名不等于加密,Payload 默认可读,不能放密码等秘密。
- “无状态”不等于零服务端状态,登出、轮换、风控和权限变更仍可能需要版本或撤销机制。
- 不应接受客户端指定的任意算法或密钥。
- Access Token 应短期、最小权限;Refresh Token 要安全存储、轮换并检测重放。
是否选择 JWT,要看服务边界、撤销要求和密钥治理,不是微服务的默认答案。
Q28: GraphQL 相比 REST 的优缺点?
答案:
优点:
| 优点 | 说明 |
|---|---|
| 精确获取 | 客户端指定需要的字段 |
| 减少请求 | 一次请求获取多个资源 |
| 强类型 | Schema 定义类型,自动校验 |
| 自文档 | Schema 即文档 |
| 版本无关 | 添加字段不影响旧客户端 |
缺点:
| 缺点 | 说明 |
|---|---|
| 缓存复杂 | 无法直接使用 HTTP 缓存 |
| 学习曲线 | 需要学习新语法 |
| N+1 问题 | 需要 DataLoader 优化 |
| 文件上传 | 需要额外处理 |
Q29: HEAD 和 GET 有什么区别?
答案:
HEAD 与 GET 语义相同,但服务器只返回响应头,不发送响应正文。它可用于检查资源是否存在、缓存验证、内容长度或最后修改时间,而不下载整个实体。
服务器应让 HEAD 的状态码和相关 Header 尽量与对应 GET 一致,但动态压缩、流式响应和应用实现可能让 Content-Length 不可用。CDN 和框架还可能自动处理 HEAD。
HEAD 不是“便宜版业务查询”的通用替代。如果生成 Header 本身就需要昂贵数据库计算,服务端成本未必明显降低。
Q30: SYN Flood 是什么?SYN Cookies 有什么作用?
答案:
SYN Flood 利用 TCP 三次握手:攻击者发送大量 SYN 却不完成最后 ACK,使服务端半连接队列和资源被占满,正常连接难以建立。
常见防护包括速率限制、扩大和监控队列、边缘清洗、缩短异常重试,以及 SYN Cookies。SYN Cookies 在收到最终 ACK 前不保存完整半连接状态,而把必要信息编码到服务端选择的初始序列号中,验证后再建立连接。
它主要缓解半连接状态耗尽,不替代应用层限流、DDoS 清洗和容量规划,也可能限制握手阶段可保存的部分 TCP 选项。
Q31: 如何优化 DNS 解析?
答案:
<!-- 1. DNS 预解析 -->
<link rel="dns-prefetch" href="//cdn.example.com">
<!-- 2. 预连接(DNS + TCP + TLS) -->
<link rel="preconnect" href="https://api.example.com">
<!-- 3. 减少域名数量 -->
<!-- 控制在 2-4 个域名 -->
<!-- 4. 使用快速 DNS -->
<!-- 如 Cloudflare 1.1.1.1 -->
Q32: HTTP/2 还有什么问题?
答案:
TCP 层队头阻塞:
- HTTP/2 解决了 HTTP 层队头阻塞
- 但底层 TCP 仍然存在队头阻塞
- 一个 TCP 包丢失会阻塞所有 HTTP/2 流
Q33: CDN 如何选择最优节点?
答案:
CDN 通过智能 DNS 实现节点选择:
| 因素 | 说明 |
|---|---|
| 地理位置 | 根据用户 IP 判断位置 |
| 网络拓扑 | 考虑 ISP、网络跳数 |
| 节点负载 | 避免热点节点 |
| 健康状态 | 剔除故障节点 |
| 实时性能 | RTT、丢包率 |
Q34: 中间人攻击是什么?如何防御?
答案:
中间人攻击:攻击者在客户端和服务器之间拦截、篡改通信。
防御措施:
| 措施 | 说明 |
|---|---|
| HTTPS | 加密传输 + 证书验证 |
| HSTS | 强制 HTTPS |
| 证书固定 | 绑定证书指纹 |
| 公钥固定 | 绑定公钥(已弃用) |
// 证书固定(移动端常用)
const pinnedCerts = ['sha256/ABC...', 'sha256/DEF...'];
function verifyPinning(serverCert: string): boolean {
const certHash = sha256(serverCert);
return pinnedCerts.includes(certHash);
}
Q35: IPv4 和 IPv6 共存时,客户端为什么需要 Happy Eyeballs?
答案:
双栈网络中,DNS 可能同时返回 A 和 AAAA 记录,但某条 IPv6 路径虽然“配置存在”却连接很慢或不可用。如果客户端严格先等 IPv6 超时再尝试 IPv4,用户会感知明显延迟。
Happy Eyeballs 会以小间隔协调尝试 IPv6 和 IPv4,优先使用较快成功的连接,并避免无节制并发。实现还会参考历史路径表现和地址排序。
它解决的是过渡期连接体验,不代表永远偏向某个协议。服务端应同时监控 IPv4/IPv6 的 DNS、握手、丢包和路由质量。
Q36: PUT 和 PATCH 的区别?
答案:
| 区别 | PUT | PATCH |
|---|---|---|
| 更新方式 | 全量替换 | 部分更新 |
| 幂等性 | 幂等 | 非幂等 |
| 请求体 | 完整资源 | 仅修改字段 |
// PUT 全量更新
PUT /users/123
{
"name": "John",
"email": "john@example.com",
"age": 30,
"address": "..."
}
// PATCH 部分更新
PATCH /users/123
{
"name": "John Doe" // 只更新 name
}
Q37: Nginx 负载均衡策略有哪些?
答案:
# 1. 轮询(默认)
upstream backend {
server 192.168.1.1;
server 192.168.1.2;
}
# 2. 加权轮询
upstream backend {
server 192.168.1.1 weight=3;
server 192.168.1.2 weight=1;
}
# 3. IP Hash
upstream backend {
ip_hash;
server 192.168.1.1;
server 192.168.1.2;
}
# 4. 最少连接
upstream backend {
least_conn;
server 192.168.1.1;
server 192.168.1.2;
}
Q38: 如何防止 Cookie 被盗取?
答案:
// 1. HttpOnly - 防止 XSS 窃取
Set-Cookie: sessionId=abc; HttpOnly
// 2. Secure - 仅 HTTPS 传输
Set-Cookie: sessionId=abc; Secure
// 3. SameSite - 防止 CSRF
Set-Cookie: sessionId=abc; SameSite=Strict
// 4. 签名 - 防止篡改
// 使用 cookie-signature 库签名
// 5. 定期更换 SessionId
// 登录后重新生成
Q39: 如何实现 JWT 的注销?
答案:
// 方案1:Token 黑名单(Redis)
async function logout(jti: string, exp: number) {
const ttl = exp - Math.floor(Date.now() / 1000);
await redis.setex(`blacklist:${jti}`, ttl, '1');
}
// 方案2:Token 版本号
async function logout(userId: number) {
await db.user.update({
where: { id: userId },
data: { tokenVersion: { increment: 1 } }
});
}
// 方案3:短期 Token + 删除 Refresh Token
async function logout(userId: number, refreshToken: string) {
await db.refreshToken.delete({
where: { userId, token: refreshToken }
});
}
Q40: 什么是 N+1 问题?如何解决?
答案:
# 查询用户列表及其文章
query {
users { # 1 次查询
posts { # N 次查询(每个用户一次)
title
}
}
}
解决方案:DataLoader
import DataLoader from 'dataloader';
// 批量加载器
const postLoader = new DataLoader(async (userIds: readonly string[]) => {
// 一次查询获取所有用户的文章
const posts = await db.post.findMany({
where: { authorId: { in: [...userIds] } }
});
// 按用户分组
const postsByUser = new Map<string, typeof posts>();
posts.forEach(post => {
const existing = postsByUser.get(post.authorId) || [];
postsByUser.set(post.authorId, [...existing, post]);
});
return userIds.map(id => postsByUser.get(id) || []);
});
// 解析器中使用
const resolvers = {
User: {
posts: (user: { id: string }) => postLoader.load(user.id)
}
};
Q41: HTTP 204 和 304 都通常没有响应体,它们有什么区别?
答案:
204 No Content 是对当前请求的成功响应,表示服务器已处理请求但没有表示内容返回,常用于更新或删除操作。它不是缓存再验证结果。
304 Not Modified 用于条件请求,表示客户端已有的缓存表示仍可使用。客户端会把 304 返回的相关响应头与本地缓存条目合并,再使用缓存中的响应体;它不是一个可独立展示的空成功页面。
因此不能把 304 当作普通 3xx 跳转,也不能用 204 回答缓存命中。
Q42: TIME_WAIT 状态有什么作用?持续时间固定吗?
答案:
主动关闭方保留 TIME_WAIT 主要有两个目的:
- 如果最后一个 ACK 丢失,对端会重发 FIN,当前端仍能再次确认。
- 让旧连接中延迟的报文在网络中消失,避免污染相同四元组的新连接。
规范通常用 2MSL 描述等待窗口,但 MSL 和具体时长由操作系统实现决定,不应死背“固定 4 分钟”。大量 TIME_WAIT 不一定是故障;应先看连接复用、短连接模式、端口范围和上游行为,不能粗暴关闭协议保护。
Q43: DNS 和 CDN 的关系?
答案:
CDN 通过 DNS 实现智能调度:
- CNAME 跳转:域名 CNAME 到 CDN 域名
- 智能解析:CDN DNS 根据用户位置、负载返回最优节点
- 就近访问:用户访问最近的边缘节点
# 示例
www.example.com
→ CNAME: example.cdn.com
→ CDN DNS 智能解析
→ 返回最近节点 IP
Q44: HTTP/3 如何解决队头阻塞?
答案:
HTTP/3 使用 QUIC 协议(基于 UDP),流之间相互独立:
// QUIC 特性
// 1. 每个流独立,丢包只影响单个流
// 2. 不需要按顺序交付
// 3. 内置拥塞控制和重传机制
| 层级 | HTTP/2 | HTTP/3 |
|---|---|---|
| 应用层 | 多路复用 ✅ | 多路复用 ✅ |
| 传输层 | TCP 队头阻塞 ❌ | QUIC 无阻塞 ✅ |
Q45: CDN 缓存没有生效怎么排查?
答案:
// 1. 检查响应头
// X-Cache: MISS 表示未命中
// 查看 Cache-Control、ETag 等
// 2. 检查缓存规则
// CDN 控制台配置是否正确
// 文件类型是否在缓存列表
// 3. 检查源站响应
// 源站是否设置了 no-cache、no-store
// 是否有 Set-Cookie(默认不缓存)
// 4. 缓存键冲突
// 查询参数不同导致缓存键不同
// 配置忽略查询参数或指定缓存键
// 5. 刷新缓存
// 手动刷新 CDN 缓存
Q46: 什么是前向安全?
答案:
前向安全(Forward Secrecy):即使长期私钥泄露,也无法解密历史通信。
实现方式:
- 使用临时密钥(ECDHE、DHE)
- 每次会话密钥独立
- 会话密钥用后销毁
// ❌ 无前向安全(RSA 密钥交换)
// 私钥泄露 → 解密所有历史流量
// ✅ 有前向安全(ECDHE)
// 私钥泄露 → 只能解密未来流量,历史安全
Q47: 各层使用什么地址?
答案:
| 层 | 地址类型 | 示例 |
|---|---|---|
| 应用层 | URL/域名 | www.example.com |
| 传输层 | 端口号 | 80、443 |
| 网络层 | IP 地址 | 192.168.1.1 |
| 数据链路层 | MAC 地址 | 00:1A:2B:3C:4D:5E |
Q48: 幂等接口为什么还需要 Idempotency-Key?
答案:
HTTP 方法语义上的幂等不能自动解决“客户端超时后不知道服务端是否成功”的问题。创建订单、支付等 POST 操作可让客户端为一次业务意图生成 Idempotency-Key。
服务端要在调用方/业务作用域内原子记录 Key、请求摘要、处理状态和最终响应:
- 相同 Key、相同请求:返回第一次结果。
- 相同 Key、不同请求:拒绝,防止误复用。
- 正在处理:返回明确状态或等待既有执行。
- 设置与业务重试窗口匹配的过期时间。
仅在前端禁用按钮不能防网络重试和重复投递;幂等键也不能替代数据库唯一约束和事务。
Q49: 前端开发中如何解决跨域?
答案:
// 开发环境:devServer 代理
// vite.config.ts
export default {
server: {
proxy: {
'/api': {
target: 'http://api.example.com',
changeOrigin: true
}
}
}
};
// 生产环境:Nginx 反向代理
// 将前端和 API 部署在同域下
// 或配置 CORS 响应头
Q50: 分布式 Session 如何处理?
答案:
推荐方案:Redis 集中存储
// 所有服务器连接同一个 Redis
import RedisStore from 'connect-redis';
app.use(session({
store: new RedisStore({ client: redisClient }),
// ...
}));
Q51: Access Token 和 Refresh Token 的作用?
答案:
| Token | 作用 | 有效期 | 存储 |
|---|---|---|---|
| Access Token | 访问资源 | 短(15分钟) | 内存/localStorage |
| Refresh Token | 获取新 Access Token | 长(7天) | httpOnly Cookie |
流程:
- 登录获取两个 Token
- 正常请求使用 Access Token
- Access Token 过期,用 Refresh Token 换新
- Refresh Token 过期,重新登录
Q52: GraphQL 如何处理认证?
答案:
// 方案1:Context 传递用户信息
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
const token = req.headers.authorization || '';
const user = verifyToken(token);
return { user };
}
});
// 解析器中验证
const resolvers = {
Mutation: {
createPost: (_, args, context) => {
if (!context.user) {
throw new AuthenticationError('Must be logged in');
}
// ...
}
}
};
// 方案2:Directive 指令
const typeDefs = gql`
directive @auth(requires: Role = USER) on FIELD_DEFINITION
enum Role {
ADMIN
USER
}
type Mutation {
deleteUser(id: ID!): Boolean! @auth(requires: ADMIN)
}
`;
Q53: TCP 如何保证可靠传输?
答案:
- 序列号 + 确认号:追踪每个字节
- 超时重传:丢包后重新发送
- 滑动窗口:流水线传输,提高效率
- 流量控制:防止接收方被淹没
- 拥塞控制:防止网络过载
Q54: 什么是 DNS 劫持?如何防护?
答案:
DNS 劫持:攻击者篡改 DNS 解析结果,将用户引导到恶意网站。
防护措施:
| 措施 | 说明 |
|---|---|
| HTTPS | 证书验证防止内容篡改 |
| DoH/DoT | 加密 DNS 查询 |
| SRI | 验证资源完整性 |
| DNSSEC | DNS 签名验证 |