计算机网络 / 04
DNS、HTTP、缓存与连接演进
怎样阅读本节
本节围绕“DNS、HTTP、缓存与连接演进”展开。先理解它要解决的系统问题,再跟着数据、控制流和状态变化阅读实现细节;不要把下面的术语表当成需要先背诵的清单。
阅读前需要知道
这些内容描述的是同一机制的不同环节:程序会在处理器上执行,并通过操作系统请求内存、文件或网络服务。;一个机制的意义,要结合它要避免的失败、等待或资源冲突来理解。;文中的图展示参与者和顺序,正文解释每一步为什么发生。。
本节术语预览
首次出现时会给出英文全称、中文名称、所属层次和解决的问题;本节出现的主要缩写如下:
- DNS:Domain Name System,域名系统
- HTTP:Hypertext Transfer Protocol,超文本传输协议
- TTL:Time To Live,生存时间
- UDP:User Datagram Protocol,用户数据报协议
- TCP:Transmission Control Protocol,传输控制协议
- HTTPS:Hypertext Transfer Protocol Secure,超文本传输安全协议
- Cache:高速缓存
- QUIC:Quick UDP Internet Connections,基于 UDP 的快速网络连接协议
- IP:Internet Protocol,互联网协议
- TLS:Transport Layer Security,传输层安全协议
- API:Application Programming Interface,应用程序编程接口
- CPU:Central Processing Unit,中央处理器
- RTT:Round-Trip Time,往返时间
建议的学习顺序
先读每个小节开头的“要解决的问题”,再读流程图和示例,最后用文末的误区、实验或面试表达检查自己能否复述因果链。
贯穿例子
以浏览器打开一个域名为例:先查询 DNS,随后建立传输连接,再发送 HTTP 请求;缓存可能跳过部分 DNS 查询,连接复用可能跳过新的握手。把这些阶段分开记录,才能判断慢在哪里。
核心讲解
一次应用请求通常先需要把人类可读的域名转换成地址,再用应用协议表达请求和响应。DNS 的缓存和层级委派影响解析延迟与结果,HTTP 的方法、状态码、头部和连接复用决定应用语义。阅读这一章时,把“名称解析”“连接建立”和“应用交换”分开计时。
本节在课程中的位置
本节属于“计算机网络”主线。学习时先把它放进整条链路:前一阶段提供输入和前置状态,本节解释一个关键机制,后一阶段再使用这些状态处理更复杂的并发、性能或故障场景。
| 阅读关系 | 页面 | 目的 |
|---|---|---|
| 课程入口 | 导学 | 了解本门课的整体问题和术语边界 |
| 建议先读 | 分层、以太网、MAC 与 ARP | 准备本节需要的概念和状态 |
| 当前章节 | DNS、HTTP、缓存与连接演进 | 建立本节的机制模型 |
| 后续复习 | TLS、完整请求链路与网络排障 | 观察本节机制如何参与更大的系统流程 |
阅读完后,尝试把本节的关键状态接回课程首页的贯穿主线;如果无法说明输入从哪里来、结果交给谁,说明前置概念还需要回看。
本节知识地图
mindmap
root((DNS(Domain Name System,域名系统) 与 HTTP(Hypertext Transfer Protocol,超文本传输协议)))
DNS 命名
域名树与 Zone
记录类型
权威服务器
DNS 解析
递归与迭代
TTL(Time To Live,生存时间) 与缓存
UDP(User Datagram Protocol,用户数据报协议) TCP(Transmission Control Protocol,传输控制协议) DoT 和 DoH
CDN
边缘调度
缓存与回源
HTTPS 终止
HTTP 语义
URL 与消息
方法和幂等
状态码
Web 状态与缓存
Cache Control 和 ETag
Cookie 与 Session
Token 和代理
HTTP 演进
HTTP 1.1
HTTP 2
HTTP 3 与 QUIC(Quick UDP Internet Connections,基于 UDP 的快速网络连接协议)
DNS 解决什么问题
应用使用域名,人和服务不应依赖固定 IP(Internet Protocol,互联网协议)。DNS 是分层、分布式命名系统,把域名解析为地址或其他记录。
常见记录:
- A:IPv4 地址。
- AAAA:IPv6 地址。
- CNAME:别名。
- MX:邮件服务器。
- TXT:文本验证和策略。
- NS:权威服务器。
解析过程
简化:
sequenceDiagram
participant A as 应用或浏览器
participant O as 操作系统和 hosts
participant R as 递归解析器
participant ROOT as 根服务器
participant TLD as 顶级域服务器
participant AUTH as 权威 DNS
A->>O: 查询域名
O->>R: 本地未命中后递归查询
R->>ROOT: 查询权威方向
ROOT-->>R: 返回 TLD 委派
R->>TLD: 查询目标域
TLD-->>R: 返回权威服务器
R->>AUTH: 查询目标记录
AUTH-->>R: 返回 A AAAA 或 CNAME
R-->>O: 缓存并返回
O-->>A: 返回解析结果
客户端通常向递归解析器发起递归请求;解析器代表客户端执行迭代查询。
实际还可能有本地代理、企业 DNS、DoH/DoT 和多级缓存。
TTL 与缓存
DNS 记录 TTL 指示缓存时长。权衡:
- TTL 长:查询少、切换生效慢。
- TTL 短:切换更快、查询压力和依赖更高。
缓存不是保证严格在某时刻同时过期,递归器和客户端实现会影响观察。
DNS 使用 UDP 还是 TCP
传统 DNS 常先用 UDP 53,响应截断、区域传送或其他需要时使用 TCP。现代还可能使用 DoT、DoH,或基于新传输。
不要回答“DNS 只使用 UDP”。
CDN
CDN 把内容和计算部署到靠近用户的边缘节点。调度可能结合:
- DNS。
- Anycast。
- 用户网络和地理位置。
- 节点健康与负载。
- 内容缓存状态。
CDN 缓存命中能减少回源延迟与带宽;动态请求仍可能回源或在边缘执行。
HTTP 是应用层协议
HTTP 定义请求与响应语义:
请求:
method path version
headers
body
响应:
version status
headers
body
HTTP 可运行在 TCP+TLS(Transport Layer Security,传输层安全协议) 或 QUIC+TLS 等传输之上。
方法语义
| 方法 | 常见语义 | Safe | Idempotent |
|---|---|---|---|
| GET | 获取表示 | 是 | 是 |
| HEAD | 只取响应元数据 | 是 | 是 |
| POST | 提交处理/创建子资源 | 否 | 通常否 |
| PUT | 用完整表示创建或替换目标 | 否 | 是 |
| PATCH | 部分修改 | 否 | 不一定 |
| DELETE | 删除目标 | 否 | 语义上是 |
幂等表示执行一次或多次的预期资源效果相同,不代表每次响应码、日志和副作用完全相同。
GET 参数在 URL、POST body 不在地址栏,不构成安全边界;两者都应使用 HTTPS 保护传输。
状态码按职责理解
- 1xx:过程信息。
- 2xx:请求成功处理。
- 3xx:重定向或缓存协商。
- 4xx:客户端请求、认证或权限问题。
- 5xx:服务端处理或上游问题。
典型区别:
- 401:缺少/无效认证。
- 403:服务器理解身份但拒绝权限。
- 404:资源不可见或不存在。
- 429:请求过多。
- 502:网关从上游得到无效响应。
- 503:暂不可用。
- 504:网关等待上游超时。
HTTP 缓存
新鲜度
Cache-Control: max-age 等指示响应在一定时间内可直接复用。
条件请求
缓存过期后可带:
- If-None-Match / ETag。
- If-Modified-Since / Last-Modified。
服务器确认未改变时返回 304,无需传完整 body。
缓存键与 Vary
不同请求头可能得到不同表示。Vary 告诉缓存哪些请求头参与区分。
flowchart TD
A["客户端请求资源"] --> B{"缓存中有对象吗"}
B -->|"否"| C["请求源站"]
B -->|"有"| D{"仍在新鲜期吗"}
D -->|"是"| E["直接返回缓存<br>无网络验证"]
D -->|"否"| F["携带 ETag 或 Last-Modified 验证"]
F --> G{"源站内容变化吗"}
G -->|"否"| H["304<br>复用旧 body"]
G -->|"是"| I["200 新 body<br>更新缓存"]
C --> I
错误缓存可能泄漏用户数据,认证响应和共享缓存需谨慎。
Cookie 与 Session
Cookie 是浏览器按域、路径等规则保存并随请求发送的小数据。
常见属性:
- Secure:只通过安全连接发送。
- HttpOnly:JavaScript 不可读取。
- SameSite:限制跨站发送。
- Max-Age/Expires。
Session 通常指服务端会话状态,Cookie 可保存 session id。两者不是互斥概念。
分布式部署需考虑 session 共享、粘性路由或无状态 token 的权衡。
HTTP/1.1
主要能力:
- 持久连接。
- Host 支持虚拟主机。
- 分块传输。
- 缓存控制。
可使用流水线,但浏览器支持和队头阻塞限制使其实际使用有限;通常通过多个 TCP 连接提高并发。
HTTP/2
- 二进制帧。
- 一个连接上多路复用多个 stream。
- HPACK 头部压缩。
- stream 优先级/流控等机制。
它解决应用层请求串行问题,但多个 stream 仍共享一个 TCP 字节流;底层丢包恢复期间可能影响连接上的多个 stream。
HTTP/3
HTTP/3 基于 QUIC(通常承载于 UDP):
- 传输层提供独立 stream。
- TLS 1.3 集成。
- 连接迁移。
- 用户态更易演进。
某个 stream 丢包通常不会像 TCP 字节流那样阻塞其他已完整 stream,但共享拥塞控制和网络资源仍会互相影响。
flowchart LR
H1["HTTP/1.1<br>持久连接与多连接"] --> H2["HTTP/2<br>单 TCP 多 stream<br>二进制帧和 HPACK"]
H2 --> H3["HTTP/3<br>QUIC 多 stream<br>集成 TLS 1.3"]
H1 -.-> P1["应用并发常依赖多 TCP 连接"]
H2 -.-> P2["仍受 TCP 连接级丢包阻塞"]
H3 -.-> P3["stream 恢复相对独立<br>仍共享路径和拥塞控制"]
Keep-Alive 的两个含义
- HTTP persistent connection:多个 HTTP 请求复用连接。
- TCP keepalive:内核在长时间空闲后探测连接是否还活着。
目的、配置和时间尺度不同。
动手观察
下面先把 DNS 命名体系和 HTTP 消息语义完整展开,再进入观察。
深入一:域名为什么存在
1. IP 不适合直接写进所有配置
服务器地址会变化:
- 扩容和迁移。
- 多地域部署。
- CDN 调度。
- 容灾切换。
- IPv4/IPv6 共存。
如果客户端硬编码 IP:
- 变更困难。
- 无法按用户位置调度。
- 运维与证书语义混乱。
2. Domain Name
直译:域名。
为服务提供层次化、可读的名字,例如:
api.example.com
DNS 不只把域名变 IP,还能发布邮件、权威服务器、验证文本和服务相关信息。
3. DNS
Domain Name System,域名系统。
它是一套:
- 分层命名空间。
- 分布式数据库。
- 查询协议。
- 缓存体系。
4. DNS 不是什么
- 不是一个全球只有一台的服务器。
- 不是所有结果永久固定。
- 不是每次请求都从根开始。
- 不是只返回 IPv4。
- 不是只使用 UDP。
深入二:域名树与权威
1. Root
域名树根写作末尾的点:
www.example.com.
日常常省略最后的点。
2. TLD
Top-Level Domain,顶级域。
例如:
.com.org.cn
3. Registrable Domain
用户可注册和管理的域名边界受公共后缀规则影响,不能一律只取最后两段。
4. Subdomain
在管理域下继续划分:
api.example.com
static.example.com
5. Zone
直译:区域。
DNS 管理可把某个子树委派给另一组权威服务器。Zone 不必等于整个域名树的直觉边界。
6. Authoritative Server
直译:权威服务器。
对某个 Zone 的记录提供权威答案。
它不是替客户端递归查询全世界,而是回答自己负责区域的信息。
7. Delegation
父区域通过 NS 等记录告诉查询者:
这个子区域应去问哪些权威服务器
这让 DNS 管理可以分布式扩展。
深入三:常见记录类型
1. A
域名到 IPv4:
example.com -> 192.0.2.10
2. AAAA
域名到 IPv6。
3. CNAME
Canonical Name,规范名称。
把一个名字指向另一个名字:
www.example.com -> edge.example-cdn.net
解析器还需继续查询目标名称对应地址。
4. NS
指定某区域的权威 DNS 服务器。
5. MX
指定域名的邮件交换服务器,并可带优先级。
6. TXT
文本记录,常用于:
- 域名所有权验证。
- 邮件 SPF/DKIM/DMARC 相关策略。
- 服务配置。
不是普通大文本存储系统。
7. PTR
反向解析:
IP -> 域名
需要相应反向区域配置,不是把 A 记录自动倒过来。
8. SOA
Start of Authority。
描述区域的权威起始信息、序列号和一些计时参数。
9. SRV
可描述某服务:
- 目标主机。
- 端口。
- 优先级。
- 权重。
客户端必须显式支持相应发现规则。
深入四:递归解析与迭代查询
1. Stub Resolver
应用/操作系统中的轻量解析客户端,通常把完整问题交给配置的递归解析器。
2. Recursive Resolver
直译:递归解析器。
代表客户端完成查询并缓存结果。
来源可能是:
- 家庭路由器/运营商。
- 企业 DNS。
- 公共 DNS。
- 本地系统服务。
3. Recursive Query
客户端希望解析器给最终答案或错误,而不是只给下一个该问谁。
4. Iterative Query
递归解析器逐步查询:
根:去问 .com
.com:去问 example.com 权威
权威:目标记录是 ...
5. 完整冷查询
应用
-> 浏览器/应用缓存
-> 操作系统缓存与 hosts
-> 递归解析器缓存
-> 根服务器
-> TLD 服务器
-> 权威服务器
-> 递归器缓存
-> 返回应用
6. 缓存命中
任意较前层已有有效结果:
- 不必走完整链路。
- 延迟更低。
- 权威压力更小。
7. CNAME 链
若答案是 CNAME:
- 还需解析规范名称。
- 可能跨另一个权威区域。
- 链过长会增加查询和故障点。
8. hosts 文件
本地静态名称映射可优先参与解析。具体顺序受系统名称服务配置影响。
深入五:TTL、缓存与一致性
1. TTL
Time To Live,生存时间。
DNS 响应中的 TTL 指示缓存结果可保留多久。
2. 长 TTL
优点:
- 查询少。
- 解析快。
- 权威压力低。
- 上游故障时已有缓存可继续一段时间。
缺点:
- IP 变更传播慢。
- 故障切换不能立即覆盖旧缓存。
3. 短 TTL
优点:
- 调度和切换更快生效。
缺点:
- 查询频率高。
- 更依赖解析器与权威可用性。
- 客户端实现可能设置自己的最小/最大策略。
4. TTL 不代表全球同时更新
不同缓存项创建时间不同:
解析器 A 在 10:00 缓存
解析器 B 在 10:04 缓存
即使 TTL 相同,过期时间也不同。
5. Negative Caching
直译:负缓存。
不存在域名等否定结果也可缓存:
- 减少重复无效查询。
- 新增记录后可能仍受旧负缓存影响。
6. 发布变更策略
计划切换前:
- 提前降低 TTL。
- 等旧长 TTL 大部分过期。
- 修改记录。
- 保持旧目标一段兼容期。
- 稳定后再提高 TTL。
仅在切换瞬间降低 TTL 对已缓存旧值的解析器无效。
深入六:DNS 传输
1. UDP 53
传统普通查询常使用 UDP:
- 无连接开销。
- 一问一答简单。
- 延迟低。
2. 截断与 TCP
响应太大时可能设置截断标志,客户端改用 TCP 重试。
3. TCP 53
还可用于:
- 大响应。
- 区域传送。
- 特定安全/部署需求。
4. EDNS
扩展 DNS 能力和 UDP 报文大小等信息,但过大 UDP 响应会增加:
- 分片风险。
- 放大攻击风险。
- 中间设备兼容问题。
5. DoT
DNS over TLS。
把 DNS 查询放在 TLS 连接中,保护客户端到解析器这一段的内容与完整性。
6. DoH
DNS over HTTPS。
通过 HTTPS 传输 DNS。
优点:
- 加密客户端到解析器。
- 可复用 Web 传输基础设施。
权衡:
- 运维可见性变化。
- 企业策略和解析路径更复杂。
- 解析器本身仍能看到查询。
7. 加密 DNS 不隐藏所有元数据
目标 IP、连接对象、流量时序以及后续访问仍可能暴露信息。
深入七:DNS 故障
1. NXDOMAIN
域名不存在的权威否定答案。
2. SERVFAIL
解析器未能完成查询:
- 权威不可达。
- DNSSEC 验证失败。
- 上游错误。
- 内部故障。
3. Timeout
没有及时收到答案:
- 网络丢包。
- 解析器过载。
- 防火墙。
- TCP 回退失败。
4. 返回错误地址
查询成功但连接到错误/旧地址:
- 记录配置错误。
- 缓存旧值。
- 分地域调度。
- split-horizon DNS。
5. Split-horizon
同一名称在不同网络返回不同结果:
- 内网地址。
- 公网地址。
- 地域/租户定制。
排障必须记录“从哪个解析器、哪个网络查询”。
深入八:CDN
1. Content Delivery Network
直译:内容分发网络。
把内容和部分计算部署到靠近用户的边缘节点。
2. 调度
可能结合:
- DNS 返回不同地址。
- Anycast。
- 用户网络和地域。
- 节点健康。
- 容量与成本。
3. Edge
直译:边缘节点。
直接面向用户连接:
- 终止 TCP/TLS。
- 缓存静态内容。
- 执行 WAF、压缩、图片处理。
- 回源获取未命中内容。
4. Origin
直译:源站。
保存原始内容或处理动态业务。
5. Cache Hit
边缘已有可用响应:
- 减少回源。
- 降低延迟。
- 节省源站带宽。
6. Cache Miss
边缘需向源站获取:
- 首个请求更慢。
- 源站压力增加。
- 可回填边缘缓存。
7. CDN 不是只复制静态文件
现代 CDN 还可能:
- 动态加速。
- 边缘计算。
- DDoS 防护。
- TLS 管理。
- 路由优化。
8. HTTPS 与 CDN
若 CDN 需要读取并缓存 HTTP 内容,通常:
- 客户端与 CDN 建 TLS。
- CDN 持有目标域名证书或被授权证书。
- CDN 到源站再建立独立安全连接。
它不是“在完全看不懂密文时直接缓存任意 HTTP 语义”。
深入九:URL
1. Uniform Resource Locator
直译:统一资源定位符。
示例:
https://example.com:8443/docs?id=10#part
2. 组成
- scheme:
https。 - host:
example.com。 - port:
8443。 - path:
/docs。 - query:
id=10。 - fragment:
part。
3. Fragment
通常由客户端处理,不随普通 HTTP 请求发送给服务器。
4. Percent-Encoding
URL 中某些字节需百分号编码:
space -> %20
字符先按编码变成字节,再进行 URL 规则处理。不能随意多次编码/解码。
5. Host 与连接地址
DNS 把 host 解析为 IP,HTTP 仍保留 Host/:authority 语义:
- 同一 IP 可托管多个站点。
- 服务器/代理按主机名路由。
- TLS SNI 也帮助选择证书。
深入十:HTTP 请求与响应
1. HTTP 语义
HTTP 定义:
- 对哪个资源。
- 执行什么方法。
- 带哪些元数据。
- 结果状态是什么。
- 内容怎样表示和缓存。
2. HTTP/1.1 请求
概念形式:
GET /items/42 HTTP/1.1
Host: api.example.com
Accept: application/json
若有 body,头部空行后继续。
3. 响应
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: ...
{...}
4. Header
承载元数据:
- 内容类型。
- 长度。
- 缓存。
- 认证。
- Cookie。
- 压缩。
- Trace。
5. Body
可以是:
- JSON。
- HTML。
- 图片。
- 二进制。
- 流式内容。
HTTP 不要求 body 一定是文本。
6. Content-Type
告诉接收方媒体类型和可能的字符编码。
仅看文件后缀或内容猜测可能产生安全和兼容问题。
7. Content-Encoding
表示内容经过 gzip、br 等编码压缩。
与字符编码不是一回事。
8. Transfer Framing
HTTP 版本需要明确一条消息 body 在哪里结束:
- Content-Length。
- chunked(HTTP/1.1)。
- 连接关闭。
- HTTP/2/3 帧和 stream 结束。
深入十一:方法、安全与幂等
1. Safe
直译:安全方法。
按协议预期不应修改服务器资源状态,例如 GET、HEAD。
不代表:
- 没有日志。
- 没有计费。
- 没有缓存更新。
- 传输内容天然安全。
2. Idempotent
直译:幂等。
相同请求执行一次或多次,对目标资源的预期效果相同。
不要求:
- 每次响应码相同。
- 日志条数相同。
- 时间戳完全相同。
3. GET
获取资源表示:
- safe。
- idempotent。
- 可按规则缓存。
不应把敏感信息放 URL,不是因为 GET 比 POST 加密弱,而是 URL 更容易进入日志、历史和引用。
4. POST
通常用于:
- 提交处理。
- 创建子资源。
- 非幂等操作。
也可通过幂等键设计安全重试。
5. PUT
通常表达用给定完整表示创建或替换已知目标 URI:
- 语义上幂等。
- 多次相同 PUT 最终资源状态相同。
6. PATCH
部分修改:
- 是否幂等取决于补丁语义。
- “设置值为 10”可幂等。
- “增加 1”通常不幂等。
7. DELETE
语义上幂等:
- 第一次删除成功。
- 后续可能返回 404。
- 最终资源仍是不存在。
8. 幂等与重试
网络超时造成模糊失败。客户端重试前要考虑:
- 方法语义。
- 幂等键。
- 服务端去重。
- 事务和唯一约束。
深入十二:状态码
1. 1xx
请求处理中的临时信息。
2. 2xx
- 200:成功并有一般响应。
- 201:资源创建成功。
- 202:已接受,处理可能尚未完成。
- 204:成功但无响应 body。
3. 3xx
- 301/308:永久重定向语义。
- 302/303/307:临时或方法处理语义有差异。
- 304:缓存验证后未修改,不是普通完整成功 body。
重定向是否保留方法需要按具体状态码规则。
4. 4xx
- 400:请求格式/参数无效。
- 401:缺少或无效认证,需要认证。
- 403:理解请求但拒绝授权。
- 404:不存在或不愿暴露。
- 409:资源状态冲突。
- 412:前置条件失败。
- 413:请求体过大。
- 429:请求过多。
5. 5xx
- 500:服务内部错误。
- 502:网关从上游获得无效响应。
- 503:服务暂不可用。
- 504:网关等待上游超时。
6. 502、503、504
| 状态 | 直觉 |
|---|---|
| 502 | 上游响应坏或连接异常 |
| 503 | 当前服务不可用/过载/维护 |
| 504 | 代理等待上游超时 |
实际网关产品的映射细节不同,需结合日志。
深入十三:HTTP 缓存
1. 缓存目标
- 降低延迟。
- 减少带宽。
- 降低源站压力。
- 在一定条件下提高可用性。
2. Private 与 Shared Cache
- 浏览器缓存:面向单用户。
- CDN/代理共享缓存:可能服务多个用户。
共享缓存必须谨慎处理认证和个性化内容。
3. Freshness
响应在新鲜期内可直接复用:
Cache-Control: max-age=60
共享缓存还可能使用 s-maxage 等指令。
4. no-cache
常见误解是“完全不缓存”。
它通常表示可存储,但再次使用前必须向源站验证。
5. no-store
指示不应存储响应,适合敏感内容等场景。
6. ETag
资源表示的验证标识:
ETag: "abc123"
过期后客户端:
If-None-Match: "abc123"
未改变时:
304 Not Modified
7. Last-Modified
时间验证:
Last-Modified
If-Modified-Since
精度和语义可能不如实体标识适合所有场景。
8. 304 与本地新鲜命中
Fresh cache hit:
- 不发网络请求。
- 直接使用缓存。
304 validation:
- 发送条件请求。
- 服务端确认未修改。
- 节省 body,但仍有网络往返。
9. Vary
告诉缓存哪些请求头决定响应表示:
Vary: Accept-Encoding
不同压缩能力需不同缓存对象。
10. Cache Key
通常包含 URI 和按 Vary 指定的请求维度。CDN 还可能自定义:
- Query 参数。
- Header。
- Cookie。
错误 key 会:
- 命中率差。
- 把一个用户内容返回给另一个用户。
11. 缓存失效
最难问题之一:
- TTL 到期。
- 版本化 URL。
- 主动 purge。
- 内容变更事件。
静态资源常用内容哈希文件名配长缓存。
深入十四:Cookie、Session 与 Token
1. Cookie
浏览器保存的小型键值数据,按域、路径、安全属性等决定何时发送。
2. Domain 与 Path
限制 Cookie 对哪些主机和路径生效。
范围设置过宽会增加暴露和意外发送。
3. Secure
只在安全连接上发送。
4. HttpOnly
阻止普通 JavaScript API(Application Programming Interface,应用程序编程接口) 读取,降低某些 XSS 窃取风险,但 Cookie 仍可能随请求发送。
5. SameSite
限制跨站请求时是否发送,帮助降低 CSRF 风险。
6. Expires/Max-Age
控制持久时间。无持久期限的 Cookie 常按会话 Cookie 处理,具体生命周期受浏览器影响。
7. Session
服务端保存会话状态:
Cookie: session_id=...
-> 服务端查 session
-> 得到用户状态
8. 分布式 Session
多实例部署选择:
- 共享 Session 存储。
- 粘性会话。
- 把可验证状态放 Token。
各有一致性、扩展性和失效权衡。
9. Token
客户端携带可验证凭据不代表服务端绝对无状态:
- 吊销。
- 权限变化。
- 密钥轮换。
- 刷新状态。
仍可能需要服务端数据。
10. Cookie 与 Session 不是二选一
Cookie 是客户端存储和自动发送机制,Session 是服务端状态概念。常用 Cookie 保存 Session ID。
深入十五:代理、网关与负载均衡
1. Forward Proxy
代表客户端访问外部:
- 客户端显式或透明使用。
- 代理知道目标。
- 可做访问控制、缓存和审计。
2. Reverse Proxy
代表服务端接收客户端:
- TLS 终止。
- 路由。
- 负载均衡。
- 缓存。
- 限流。
3. Host 与 X-Forwarded
经过代理后需要传递:
- 原始主机。
- 客户端地址。
- 协议。
- Trace 信息。
这些头部不能无条件信任外部客户端,应由可信代理覆盖/追加并建立信任边界。
4. Gateway Timeout
504 通常由代理报告其等待上游超时。真正慢点可能是:
- 上游排队。
- 数据库。
- 网络。
- 超时层级不一致。
深入十六:HTTP/1.1
1. Persistent Connection
同一 TCP 连接处理多个请求:
- 减少 TCP/TLS 握手。
- 减少临时端口和 TIME_WAIT。
- 保留拥塞窗口等连接状态。
2. Host
允许同一 IP/端口托管多个虚拟主机。
3. Content-Length
明确 body 长度。
4. Chunked Transfer
发送方不知道完整长度时,可分块传输并用结束块表示完成。
5. Pipelining
客户端可连续发送多个请求,不等前一个响应。
限制:
- 响应仍按请求顺序。
- 前一个响应慢会阻塞后面。
- 中间设备和错误处理复杂。
- 浏览器实践中使用有限。
6. 多连接
浏览器常为同一来源建立多个 TCP 连接提高并发,但:
- 每条都要握手。
- 各有拥塞状态。
- 占连接资源。
深入十七:HTTP/2
1. Binary Framing
把 HTTP 消息拆成二进制 frame,不再只靠文本行解析传输结构。
2. Stream
一个连接中有多个逻辑 stream:
TCP connection
├── stream 1
├── stream 3
└── stream 5
3. Multiplexing
不同 stream 的帧可交错传输:
- 不必等一个完整响应结束再传另一个。
- 减少应用层 HTTP/1.1 队头阻塞。
4. HPACK
压缩重复 HTTP 头部:
- 静态表。
- 动态表。
- 索引表示。
状态压缩也带来实现和安全复杂性。
5. Stream Flow Control
HTTP/2 有连接级和 stream 级流控:
- 防止一个接收方被数据淹没。
- 配置不当会限制吞吐。
6. TCP 队头阻塞
所有 stream 最终共享一条 TCP 有序字节流:
- 底层某段丢失。
- TCP 必须补齐缺口。
- 后续已到达字节不能越过缺口交给上层。
- 多个 stream 可能共同等待。
7. 一个连接也不是永远最佳
- 单连接丢包影响多个 stream。
- 单连接拥塞窗口共享。
- 连接可能有单点故障。
- 实际客户端和服务端可按策略使用多个连接。
深入十八:HTTP/3 与 QUIC
1. QUIC
基于 UDP 承载的用户态传输协议:
- 自己实现可靠性和拥塞控制。
- 集成 TLS 1.3。
- 提供多 stream。
- 使用 Connection ID。
2. 为什么使用 UDP
不是为了放弃可靠性,而是:
- 在用户态更快演进。
- 避免部署新 IP 传输协议的中间设备兼容障碍。
- 由 QUIC 自己提供可靠 stream。
3. 独立 stream
某个 stream 丢失数据:
- 该 stream 等待重传。
- 其他已完整 stream 通常可以继续交付。
减少 TCP 连接级队头阻塞。
4. TLS 集成
QUIC 握手与 TLS 1.3 更紧密结合,减少建立传输与安全连接的重复往返。
5. Connection ID
连接不只绑定传统四元组,可在客户端网络地址变化时继续识别连接,例如 Wi-Fi 切换蜂窝网络。
6. 仍然共享什么
多个 stream 仍共享:
- 连接拥塞控制。
- 路径带宽。
- CPU(Central Processing Unit,中央处理器)。
- 连接级流控等资源。
所以不是完全互不影响。
7. HTTP/3 不保证任何网络都更快
受:
- UDP 是否被限制。
- 实现质量。
- RTT(Round-Trip Time,往返时间) 与丢包。
- 连接复用。
- CPU 和加密。
影响。客户端常需要回退策略。
深入十九:Keep-Alive 三个概念
1. HTTP Persistent Connection
多个 HTTP 请求复用同一传输连接。
2. TCP Keepalive
内核在连接长期空闲后发送探测,判断对端是否仍可达。
3. Application Heartbeat
应用协议主动发送 ping/pong:
- 检测业务处理链。
- 更灵活的时间配置。
- 增加流量和状态。
三者目的和时间尺度不同,不能只说“开 keepalive”。
深入二十:一次 HTTP 缓存请求
首次:
客户端无缓存
-> GET
-> 200 + body
-> Cache-Control max-age=60
-> ETag "v1"
-> 保存
60 秒内:
直接使用本地缓存
-> 无网络请求
过期后:
GET + If-None-Match: "v1"
-> 未修改
-> 304
-> 客户端复用旧 body
内容已更新:
GET + If-None-Match: "v1"
-> 200 + 新 body + ETag "v2"
补充面试题:直接背诵
Q1:DNS 解析过程
应用先查自身缓存,再经过系统缓存、hosts 和配置的递归解析器。递归器命中缓存就直接返回,否则代表客户端依次向根、TLD 和权威服务器做迭代查询,缓存 TTL 后返回。CNAME 可能引出额外名称查询,实际还可能使用企业代理、DoH 或分地域解析。
Q2:递归与迭代区别
递归查询要求被询问者给最终答案或错误,客户端通常向递归解析器这样请求;迭代查询返回当前已知答案或下一步该问的权威,递归解析器通常用它逐级查询根、TLD 和权威服务器。
Q3:DNS TTL 如何权衡
长 TTL 减少查询、降低延迟和权威压力,但记录变更与故障切换传播慢;短 TTL 切换快但增加查询和依赖。变更前应提前降低 TTL 并等待旧缓存过期,不能在切换瞬间降低就期待全球立即生效。
Q4:DNS 使用 UDP 还是 TCP
传统普通查询常先用 UDP 53;响应截断、大响应、区域传送等会使用 TCP。现代还有 DoT 和 DoH。因此不能回答 DNS 只使用 UDP,具体取决于响应大小、操作类型和部署。
Q5:HTTP 幂等是什么意思
相同请求执行一次或多次,对目标资源的预期效果相同,不要求每次响应码、日志或时间戳完全一致。GET、PUT、DELETE 语义上通常幂等,POST 通常不是,但可通过幂等键和服务端去重支持安全重试。
Q6:401 与 403
401 通常表示缺少或无效认证,需要提供有效身份凭据;403 表示服务器理解请求和身份但拒绝授权。实际系统也可能用 404 隐藏敏感资源存在性。
Q7:no-cache 与 no-store
no-cache 通常允许存储,但每次复用前必须向源站验证;no-store 表示不应存储响应。名字容易误导,缓存行为还要结合 private/public、max-age 和客户端实现。
Q8:304 与浏览器直接命中区别
新鲜缓存可直接使用,不产生网络往返;304 表示缓存已需要验证,客户端发条件请求,服务端确认未修改后只返回元数据,客户端复用已有 body。304 省带宽但仍有网络延迟。
Q9:HTTP/1.1、2、3 演进
HTTP/1.1 用持久连接并常借多 TCP 连接提高并发;HTTP/2 用二进制帧和 stream 在单 TCP 连接多路复用并压缩头部,但仍受 TCP 连接级丢包阻塞;HTTP/3 基于 QUIC,集成 TLS 1.3,让 stream 丢包恢复相对独立并支持连接迁移。
Q10:HTTP keep-alive 与 TCP keepalive
HTTP persistent connection 是多个请求复用连接,减少握手;TCP keepalive 是内核在长时间空闲后探测连接是否仍可达;应用心跳又能验证更高层业务状态。三者目的、配置和时间尺度不同。
补充理解检查
判断题
- DNS 是全球一台中心服务器。
- 递归解析器每次都必须从根查询。
- CNAME 直接保存目标 IP。
- TTL 到期时全球缓存同时失效。
- DNS 只使用 UDP。
- URL fragment 通常随 HTTP 请求发送。
- POST body 因不在地址栏所以无需 HTTPS。
- DELETE 语义幂等表示每次响应必须完全相同。
- no-cache 表示绝对不能存储。
- 304 响应通常需要一次网络验证。
- Cookie 和 Session 是互斥方案。
- HTTP/2 多路复用消除了 TCP 层队头阻塞。
- QUIC 基于 UDP 所以不可靠。
答案:1 错,2 错,3 错,4 错,5 错,6 错,7 错,8 错,9 错,10 对,11 错,12 错,13 错。
讲解题
- 画出根、TLD、权威和递归器。
- 解释 DNS 变更前为什么要提前降 TTL。
- 比较 A、AAAA、CNAME、NS 和 MX。
- 拆解一个完整 URL。
- 为创建订单接口设计幂等重试。
- 画出 max-age + ETag 的三次请求。
- 解释 Vary 配置错误怎样泄漏内容。
- 比较浏览器 Cookie、服务端 Session 和 Token。
- 画出 HTTP/2 stream 如何映射到一个 TCP 字节流。
- 解释 QUIC 为什么仍需要拥塞控制。
dig example.com
dig +trace example.com
curl -v https://example.com/
curl -I https://example.com/
curl --http2 -I https://example.com/
观察 DNS 记录、响应头、缓存字段、连接复用和协议版本。
常见误区
- DNS 不只使用 UDP。
这些内容描述的是同一机制的不同环节:POST 不因参数在 body 就更安全。;HTTP 幂等不等于每次响应完全相同。;Cookie 在客户端,Session 状态通常在服务端,两者可配合。;HTTP/2 多路复用没有消除 TCP 层丢包影响。;CDN 不只是“复制静态文件”,也包含调度、回源和边缘能力。。
面试表达
HTTP/1.1、HTTP/2、HTTP/3 怎样演进?
HTTP/1.1 通过持久连接等改进复用,但并发常依赖多连接;HTTP/2 用二进制帧和 stream 在单 TCP 连接多路复用,并压缩头部,但仍受 TCP 连接级丢包恢复影响;HTTP/3 基于 QUIC,把 stream、TLS 1.3 和连接迁移整合到用户态传输,减少跨 stream 队头阻塞并便于演进。
追问链
- 递归 DNS 和迭代查询分别是谁做?
- TTL 长短怎样权衡?
- 304 与 200 from cache 有什么差异?
- 幂等与重试有什么关系?
- HTTP keep-alive 与 TCP keepalive 有什么区别?
理解检查
- 画出递归解析器查询权威 DNS 的过程。
- 判断一组方法的 safe/idempotent 属性。
- 设计带 ETag 的条件请求。
- 解释 HTTP/2 stream 与 TCP 字节流的关系。
| 上一课:UDP 与 TCP | 下一课:TLS 与排障 → |
核心模型
先建立“输入、处理单元、输出和失败路径”的模型,再阅读具体实现。术语只有放进这条因果链,才不会变成孤立的背诵点。
常见误区
这些内容描述的是同一机制的不同环节:把名词定义当成机制解释,跳过状态和时间顺序。;把“通常如此”说成“任何平台都如此”,忽略实现和配置差异。;看到性能问题就直接调参数,没有先确认瓶颈位于哪一层。。
理解检查
- 本篇首先解决什么问题?
- 核心状态由谁保存,什么时候更新?
- 设计的主要代价和边界条件是什么?
可观察实验
选一个最小可运行例子,记录输入、关键状态和输出,再把异常结果与文中的失败路径逐项对照。
术语卡片
下表只收录本篇实际使用的主要缩写。阅读正文时先理解它在流程中的角色,复习时再用这张表回查全称和定义。
| 缩写 | 英文全称 | 中文名称 | 在本篇中的定义或作用 |
|---|---|---|---|
| DNS | Domain Name System | 域名系统 | 应用层,把域名解析为 IP 地址 |
| HTTP | Hypertext Transfer Protocol | 超文本传输协议 | 应用层,定义请求和响应的消息语义 |
| TTL | Time To Live | 生存时间 | IP 数据包允许经过的最大跳数 |
| UDP | User Datagram Protocol | 用户数据报协议 | 传输层,提供无连接的数据报传输 |
| TCP | Transmission Control Protocol | 传输控制协议 | 传输层,为应用提供有序可靠的字节流 |
| QUIC | Quick UDP Internet Connections | 基于 UDP 的快速网络连接协议 | 在 UDP 之上实现可靠、安全和多路复用传输 |
| IP | Internet Protocol | 互联网协议 | 网络层,负责跨网络寻址和转发数据包 |
| TLS | Transport Layer Security | 传输层安全协议 | 安全协议,提供身份认证、机密性和完整性 |
| API | Application Programming Interface | 应用程序编程接口 | 程序调用另一组件功能的约定接口 |
| CPU | Central Processing Unit | 中央处理器 | 执行机器指令并协调计算的处理器核心 |
| RTT | Round-Trip Time | 往返时间 | 请求从发送端到达对端再返回所需的时间 |