应用交付:RPC、WebSocket、代理、负载均衡与 CDN
内容摘要:用户访问的通常不是一台裸露的应用服务器,而是一条由域名系统(Domain Name System,DNS)、内容分发网络(Content Delivery Network,CDN)、四层或七层负载均衡器、网关、代理和后端实例组成的交付链路。本章先澄清远程过程调用(Remote Procedure Call,RPC)与 HTTP 的关系,再解释 WebSocket 的握手与帧,最后沿真实数据路径分析代理、负载均衡、健康检查、连接复用、缓存、超时、重试和故障排查。
一、先建立正确边界
1、HTTP 与 RPC 不是同一维度
- HTTP 是应用层协议,定义请求方法、状态码、字段、缓存等语义以及不同版本的线上编码。
- RPC 是“像调用本地函数一样调用远端服务”的编程与交互模型,通常还包含接口定义语言(Interface Definition Language,IDL)、序列化、代码生成、服务发现、截止时间和错误模型。
- RPC 可以运行在 HTTP/2 上,例如 gRPC;也可以使用自定义 TCP 协议。REST 风格接口也常使用 HTTP。
因此,“HTTP 还是 RPC”不是严格二选一。更准确的问题是:
- 接口是否面向浏览器、开放生态还是内部服务?
- 是否需要 IDL、强类型和代码生成?
- 是否需要双向流、多路复用、截止时间传播和统一错误模型?
- 中间代理、可观测性、安全设备是否理解该协议?
| 维度 | 通用 HTTP API | 典型 gRPC |
|---|---|---|
| 传输与编码 | HTTP/1.1、HTTP/2 或 HTTP/3;JSON 等 | 通常 HTTP/2;Protocol Buffers 常见 |
| 接口契约 | OpenAPI 等,可选 | .proto IDL 与生成代码 |
| 浏览器直连 | 支持广泛 | 原生限制较多,常需 gRPC-Web/代理 |
| 流式调用 | SSE、WebSocket、分块响应等 | 客户端流、服务端流、双向流 |
| 可读性 | 文本格式便于人工调试 | 二进制高效但需 schema 解码 |
| 失败语义 | HTTP 状态码 + 业务体 | gRPC status + trailers |
| 适合场景 | 开放 API、Web、跨组织集成 | 内部强契约服务、低延迟流式调用 |
工程边界:二进制编码不自动意味着端到端更快。总耗时还受排队、序列化、网络 RTT、重试、连接复用、服务端计算和下游依赖影响,必须实测。
2、WebSocket 解决什么问题
WebSocket 是在一条长连接上提供全双工消息通道的应用层协议。它适合聊天、协作编辑、实时状态推送和游戏信令等双向低延迟场景。
它不是唯一的“服务端推送”方案:
| 方案 | 方向 | 连接特征 | 适用场景 | 主要限制 |
|---|---|---|---|---|
| 短轮询 | 客户端主动 | 周期性新请求 | 低频更新、实现简单 | 空请求多、时延受轮询周期影响 |
| 长轮询 | 主要服务端响应 | 请求挂起后返回,再重建 | 兼容传统 HTTP 基础设施 | 重连与并发管理复杂 |
| Server-Sent Events(SSE) | 服务端到客户端 | HTTP 长响应 | 单向事件流、浏览器自动重连 | 不提供原生双向消息 |
| WebSocket | 双向 | 长连接、消息帧 | 高频双向交互 | 连接容量、心跳、代理超时需单独治理 |
| WebTransport | 多流/数据报 | HTTP/3/QUIC | 新型实时应用 | 支持度与基础设施成熟度需实测 |
二、端到端应用交付路径
每增加一跳,都会引入新的:
- 连接与队列;
- 超时和重试;
- 证书与身份边界;
- 缓存与一致性边界;
- 日志、指标和追踪点;
- 故障模式与容量上限。
排障时必须画出实际路径,不能只说“请求经过了负载均衡”。
三、正向代理、反向代理与网关
| 类型 | 代表谁 | 典型用途 | 服务端看到的直接对端 |
|---|---|---|---|
| 正向代理 | 客户端 | 出网控制、匿名、缓存、审计 | 正向代理 |
| 反向代理 | 服务端 | TLS 终止、路由、缓存、限流 | 反向代理 |
| API 网关 | API 提供方 | 认证、配额、协议转换、路由 | 网关 |
| 服务网格数据平面 | 工作负载 | 服务间治理、mTLS、遥测 | sidecar/节点代理,取决于实现 |
1、代理会终止并重建连接
典型七层反向代理不是简单“转发同一个 TCP 包”:
两段连接可以具有不同的:
- 地址与端口;
- TCP 拥塞窗口和重传;
- TLS 版本、证书与双向认证策略;
- HTTP 版本;
- 超时、缓冲与连接池;
- 抓包内容和故障原因。
客户端抓包正常,不代表代理到后端的连接正常。
2、客户端地址如何传播
七层代理后的后端通常只能从 socket 看到代理地址。若业务确实需要原始客户端信息,可使用:
- 标准化
Forwarded字段(RFC 7239); - 生态常用但非统一标准的
X-Forwarded-For、X-Forwarded-Proto; - 四层场景的 PROXY protocol(实现规范,不是 IETF RFC);
- 透明代理/保留源地址能力,具体依赖网络与平台。
安全红线:入口代理必须删除或覆盖来自不可信客户端的转发字段。应用只信任由明确代理链写入的位置,否则攻击者可伪造来源地址、协议和主机名。
四、四层与七层负载均衡
| 维度 | 四层负载均衡(L4) | 七层负载均衡(L7) |
|---|---|---|
| 决策信息 | IP、端口、传输协议、连接状态 | Host、path、header、cookie、RPC method 等 |
| 典型实现 | NAT、DSR、IPVS、传输层代理 | Nginx、HAProxy、Envoy、云应用 LB |
| TLS | 常透传,也可由其他层终止 | 常在此终止或重新加密 |
| 连接 | 转发或代理 TCP/UDP 流 | 解析应用协议,通常两段连接 |
| 优点 | 开销低、协议透明、吞吐高 | 路由灵活、可观测性与安全策略丰富 |
| 限制 | 不理解业务语义 | CPU/内存开销更高,协议兼容更复杂 |
| 常见故障 | 哈希偏斜、连接跟踪耗尽、回程不对称 | 头部/超时限制、协议升级失败、重试放大 |
1、转发模式不是一个实现
- 网络地址转换(Network Address Translation,NAT):负载均衡器改写地址/端口,需要正确处理回程。
- 直接服务器返回(Direct Server Return,DSR):入站经负载均衡器,响应可直接由后端返回,性能高但网络配置复杂。
- 全代理(full proxy):负载均衡器分别维护客户端连接和后端连接,便于治理但增加状态和资源消耗。
- Anycast + ECMP:先把流量引到某个站点或节点,再做本地负载均衡;路由收敛与连接稳定性需单独设计。
五、调度算法与状态
| 算法 | 决策依据 | 优点 | 风险/边界 |
|---|---|---|---|
| Round Robin | 轮询 | 简单、无状态 | 不感知请求成本与实例容量 |
| Weighted Round Robin | 静态权重 | 可表达容量差异 | 权重需要持续校准 |
| Least Connections | 活跃连接数 | 适合连接耗时差异 | HTTP/2/gRPC 长连接会扭曲连接数含义 |
| Least Request / EWMA | 请求或延迟 | 更接近实时负载 | 需要可靠采样,可能对抖动敏感 |
| 哈希 | 源地址、URI、键 | 稳定映射 | 节点变化导致重映射和热点 |
| 一致性哈希 | 哈希环/虚拟节点 | 节点变化时减少重映射 | 仍需处理热点、权重和故障迁移 |
| Power of Two Choices | 随机选两个取较轻者 | 低开销且均衡性好 | 指标滞后时仍可能偏斜 |
关键事实:
- “连接均衡”不等于“请求均衡”。一个 gRPC/HTTP/2 连接可承载大量并发流。
- “请求数均衡”不等于“资源均衡”。请求成本可能相差几个数量级。
- 一致性哈希不等于会话不会丢失。节点故障和扩缩容仍会迁移一部分键。
六、健康检查、摘除与慢启动
1、存活与就绪必须分开
- 存活检查(liveness):进程是否需要重启。
- 就绪检查(readiness):实例当前是否能接收新流量。
- 启动检查(startup):慢启动应用是否已经完成初始化。
- 被动检查:根据真实请求的连接失败、超时或响应码判断。
- 主动检查:负载均衡器周期性请求专用端点。
2、常见错误
- 检查端点永远返回 200,却不验证关键依赖和事件循环。
- 检查过深,把单个非关键下游抖动放大为整个集群摘除。
- 检查间隔过短、阈值过低,导致实例在健康/不健康间振荡。
- 恢复后立即满量接流量,没有慢启动(slow start)或预热。
- 摘除只停止新请求,没有连接排空(connection draining)。
健康检查设计要回答:检查什么、谁检查、从哪里检查、连续几次、多久超时、恢复阈值、摘除后如何排空、监控如何告警。
七、WebSocket:握手、帧与代理
1、HTTP/1.1 Opening Handshake
RFC 6455 的 WebSocket 通常从 HTTP/1.1 Upgrade 开始:
GET /chat HTTP/1.1
Host: ws.example
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: https://app.example服务端接受时返回:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=Sec-WebSocket-Accept 是 Base64(SHA-1(key + GUID)) 的结果,用于证明服务端理解 WebSocket 握手,不是身份认证或数据加密。机密性和服务身份依赖 wss:// 下的 TLS。
HTTP/2 可按 RFC 8441 使用扩展 CONNECT;HTTP/3 对应 RFC 9220。支持能力取决于客户端和代理,不能假设所有链路都支持。
2、帧与消息边界
WebSocket 在 TCP 字节流上定义自己的帧:
| 字段 | 作用 | 注意事项 |
|---|---|---|
| FIN | 是否为消息最后一个片段 | 一个消息可跨多个帧 |
| opcode | continuation/text/binary/close/ping/pong | 控制帧有长度和分片限制 |
| MASK | 载荷是否掩码 | 客户端到服务端必须掩码;这不是加密 |
| payload length | 7/16/64 位长度编码 | 实现必须限制最大消息和聚合内存 |
| masking key | 32 位掩码键 | 仅客户端帧携带 |
3、代理链的生产约束
- HTTP/1.1 代理必须正确传递 Upgrade 语义;逐跳字段不能机械透传。
- 空闲超时若小于业务静默周期,连接会被代理主动关闭。
- Ping/Pong 是协议级保活;业务心跳还可验证应用处理能力,两者不能混用。
- 负载均衡器按连接调度,长连接会让扩容后的新实例长期接不到均衡流量。
- 发布时应先停止新连接,再等待存量连接排空,并让客户端使用带抖动的退避重连。
- 会话状态应外置或可重建;依赖粘性会话会增加故障迁移难度。
八、RPC/gRPC 的数据路径
1、必须一起设计的机制
| 机制 | 正确问题 | 常见失败 |
|---|---|---|
| 服务发现 | 地址多久更新、连接何时重建? | DNS 已变化但长连接仍指向旧实例 |
| 截止时间 | 请求最晚何时完成?是否向下游传播? | 每层独立超时,总耗时失控 |
| 重试 | 哪些状态可重试?请求是否幂等? | 重试写请求导致重复副作用 |
| 负载均衡 | 按连接还是按请求/stream? | 少量长连接导致实例负载偏斜 |
| 流控/背压 | 消费方变慢时谁停止读取? | 缓冲无限增长或尾延迟恶化 |
| 错误模型 | 传输错误与业务错误如何区分? | 把业务拒绝误判成网络故障 |
| 观测 | method、status、deadline、attempt 是否可见? | 只有平均延迟,无法定位重试放大 |
2、截止时间、重试与请求放大
假设入口最多重试 2 次,下游也最多重试 2 次,最坏尝试次数不是 4,而可能是:
(1 + 2) × (1 + 2) = 9 次下游尝试正确做法:
- 传递一个端到端截止时间,而不是每跳重新给完整超时。
- 只对明确的瞬时错误重试。
- 预算包含排队、连接、TLS、首字节和重试退避。
- 写请求使用幂等键、去重或条件更新。
- 采用指数退避(exponential backoff)和随机抖动(jitter)。
- 限制每层最大尝试次数和全局重试预算。
九、CDN:缓存不是“离用户近”这么简单
1、基本数据路径
CDN 的收益包括:
- 减少用户到内容的网络 RTT;
- 静态内容在边缘命中,降低源站带宽与请求压力;
- 在边缘完成 TLS、压缩、协议协商和部分安全防护;
- 通过 Anycast/DNS 调度把客户端引到合适的接入点。
2、缓存键与一致性
缓存键通常至少包含 scheme、host、path、query 的某种组合,也可能包含由 Vary 指定的请求字段。错误缓存键会造成:
- 不同用户内容互串;
- 查询参数被忽略导致旧内容;
- 把认证响应缓存为公开响应;
- 多种编码或语言互相污染;
- 缓存碎片化导致命中率下降。
需要同时设计:
Cache-Control、Expires、ETag与条件请求;s-maxage、stale-while-revalidate、stale-if-error;- 主动失效(purge/invalidation)的延迟与费用;
- 源站屏蔽、回源并发合并和热点保护;
- Range 请求、大对象、流媒体与分片缓存;
- 签名 URL/Cookie 和防盗链的信任边界。
一致性边界:CDN purge 通常不是跨所有节点的原子事务。发布系统必须允许短时间新旧版本并存,静态资源宜使用内容哈希文件名。
十、TLS 终止与信任边界
| 模式 | 客户端到边缘 | 边缘到后端 | 风险重点 |
|---|---|---|---|
| TLS passthrough | TLS 直达后端 | 同一连接/流 | L7 能力有限,SNI 路由边界 |
| Edge termination | TLS | 明文 HTTP | 内网仍可能被窃听/篡改 |
| Re-encryption | TLS | 新 TLS 连接 | 后端证书、SNI、信任链必须验证 |
| mTLS to origin | TLS | 双向 TLS | 客户端证书轮换与身份授权 |
不要把“云内网”自动视为可信边界。边缘到源站至少应有网络访问控制和服务身份验证;高风险场景使用 mTLS。
十一、超时、缓冲与连接池
1、超时必须分阶段
- 上游总截止时间必须大于必要阶段之和,但不能无限大。
- 代理的后端超时应小于客户端总超时,为错误转换和回退保留预算。
- 长响应的“总时长”和“空闲时长”是不同约束。
- WebSocket/gRPC stream 不能套用普通短请求的响应超时。
- 连接池需要限制总连接、每目标连接、空闲连接、最大连接寿命和等待队列。
2、缓冲的取舍
- 请求缓冲可保护慢客户端影响后端,但增加延迟和磁盘/内存占用。
- 响应缓冲便于重试和缓存,但破坏真正流式传输。
- 禁用缓冲适合 SSE、WebSocket、流式 RPC,但后端会直接承受慢消费者背压。
十二、最小可复现实验:观察两段连接与负载分配
1、环境
- Linux/macOS/Windows(Docker Desktop 亦可)
- Docker、
curl - 实验只绑定
127.0.0.1,不接触生产网络
以下使用 Nginx 开源版演示被动失败处理与轮询。开源版是否支持主动健康检查取决于版本和模块,不能把商业版或云 LB 能力套用到所有环境。
2、启动两个可区分的源站
docker network create app-delivery-lab
docker run -d --rm --name origin-a --network app-delivery-lab \
hashicorp/http-echo:1.0 -text='origin-a' -listen=:8080
docker run -d --rm --name origin-b --network app-delivery-lab \
hashicorp/http-echo:1.0 -text='origin-b' -listen=:8080创建隔离实验配置 nginx.conf:
events {}
http {
log_format upstream '$remote_addr "$request" status=$status '
'upstream=$upstream_addr upstream_status=$upstream_status '
'request_time=$request_time upstream_time=$upstream_response_time';
upstream app_backend {
server origin-a:8080 max_fails=2 fail_timeout=5s;
server origin-b:8080 max_fails=2 fail_timeout=5s;
keepalive 16;
}
server {
listen 8080;
access_log /dev/stdout upstream;
location / {
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Forwarded "for=$remote_addr;proto=$scheme;host=$host";
proxy_set_header X-Request-ID $request_id;
proxy_set_header Connection "";
proxy_pass http://app_backend;
}
}
}启动代理。生产环境应固定经过安全评估的镜像 digest;下面版本仅为实验示例,执行前以镜像仓库实际可用版本为准:
docker run -d --rm --name edge-proxy \
--network app-delivery-lab \
-p 127.0.0.1:18080:8080 \
-v "$PWD/nginx.conf:/etc/nginx/nginx.conf:ro" \
nginx:1.27-alpine重复请求:
for i in 1 2 3 4; do
curl -fsS http://127.0.0.1:18080/
done预期结果(具体顺序受连接复用、容器解析与实现影响):
origin-a
origin-b
origin-a
origin-b预期能在代理日志中看到:
- 客户端直接连接的是
127.0.0.1:18080; upstream为origin-a:8080或origin-b:8080的容器地址;- 客户端请求时间与后端响应时间是不同指标。
3、注入后端故障
docker stop origin-a
for i in 1 2 3 4; do
curl -sS -o /dev/null -w '%{http_code}\n' \
http://127.0.0.1:18080/
done可能先出现一次 502,随后请求落到 origin-b;是否重试、失败几次后摘除取决于 Nginx 配置与请求类型。不要预先声称所有请求都无损切换。
检查证据:
docker logs edge-proxy
docker inspect origin-b --format '{{json .NetworkSettings.Networks}}'4、抓包
Linux 上可在 loopback 抓客户端到代理的连接:
sudo tcpdump -i lo -nn -s 0 -c 100 \
'tcp port 18080'容器内部或宿主 bridge 上抓代理到后端的第二段连接,接口名因 Docker 实现不同,需先用 ip link 和 docker network inspect app-delivery-lab 确认,不能照抄接口名。
5、清理
docker rm -f edge-proxy origin-a origin-b 2>/dev/null || true
docker network rm app-delivery-lab
rm -f nginx.conf执行状态:本章 Docker/Nginx 实验未在当前环境执行,输出为预期模式而非伪造实测。执行时应记录镜像 digest、Docker/Nginx 版本、请求次数和完整日志。
十三、测试与验证清单
1、HTTP/RPC
- 验证连接建立、协议协商、序列化和响应状态分别耗时。
- 验证 deadline 是否跨代理和下游传播。
- 对读写请求分别测试超时前、超时后、响应中断和重复提交。
- 检查重试次数、attempt 标记和幂等键。
- HTTP/2/gRPC 测试单连接多 stream、GOAWAY、RST_STREAM 和流控。
2、WebSocket
- 验证 Upgrade/extended CONNECT 成功与失败。
- 验证文本、二进制、分片、Ping/Pong、Close 帧。
- 空闲超过各层超时,确认由谁关闭。
- 代理重启、实例摘除、网络切换时验证重连退避和消息语义。
- 限制最大帧、最大消息、连接数和每连接发送速率。
3、负载均衡/CDN
- 正常、慢、拒绝连接、超时、错误码各自如何计入健康状态。
- 扩缩容后连接与请求是否重新均衡。
- 缓存键是否包含必要维度,认证响应是否禁止共享缓存。
- purge 后各区域传播时间与新旧版本兼容性。
- 回源失败时 stale 策略是否符合数据一致性要求。
十四、常见故障与证据
| 现象 | 可能层次 | 优先证据 |
|---|---|---|
| 客户端 502 | 代理到后端连接失败/无合法响应 | 代理 access/error log、upstream address/status |
| 客户端 503 | 无健康后端、过载、主动拒绝 | 健康检查、后端池、队列与限流指标 |
| 客户端 504 | 代理等待后端超时 | 分阶段时延、后端日志、连接与依赖追踪 |
| WebSocket 立即断开 | Upgrade 字段、协议不兼容、鉴权失败 | 101 响应、代理配置、Close code |
| WebSocket 周期性断开 | 空闲超时、NAT 映射过期、心跳缺失 | 断开周期、各层 idle timeout、Ping/Pong |
| gRPC 偶发 UNAVAILABLE | 连接迁移、GOAWAY、无健康实例、LB 偏斜 | gRPC status、attempt、HTTP/2 frame、代理日志 |
| 新实例无流量 | 长连接按连接均衡 | 每实例连接数与 stream/request 数 |
| CDN 命中错误内容 | 缓存键/Vary/认证边界错误 | Age、Via、cache status、请求/响应字段 |
| 源站被打满 | 命中率下降、缓存穿透、回源并发无保护 | hit ratio、origin QPS、collapsed forwarding |
排查顺序:
- 明确客户端最终错误、请求 ID、时间范围和受影响比例。
- 确认 DNS 返回和实际边缘/负载均衡节点。
- 分别验证客户端到边缘、边缘到后端两段连接。
- 对齐 access log、error log、健康状态、后端日志和追踪。
- 检查最近发布、路由、证书、缓存键、超时与重试变更。
- 只在获得证据后调整参数;先限流/回滚,再做长期修复。
十五、性能与容量
至少监控:
- 新连接率、活跃连接、连接复用率、握手时延;
- 每秒请求/stream、并发、等待队列、拒绝数;
- 上游连接失败、重置、超时和重试;
- p50/p95/p99 总时延与 upstream 时延;
- 各实例请求、连接、CPU、内存和队列分布;
- CDN 请求/字节命中率、回源率、回源带宽、purge 延迟;
- WebSocket 连接数、连接时长、消息率、待发送字节和重连率。
容量不能只按 QPS 估算。长连接系统常由连接数 × 每连接内存 + 心跳包速率 + TLS 状态 + 文件描述符决定;大对象 CDN 则可能由带宽、缓存空间和回源峰值决定。
十六、安全风险与加固
- 只接受可信代理写入的客户端地址字段,防止 IP 伪造。
- 限制请求行、字段、body、WebSocket frame/message 和 gRPC message 大小。
- 入口和后端都配置连接、并发、速率和队列上限。
- TLS 终止后到后端继续验证服务身份;敏感链路使用 mTLS。
- 防止开放正向代理和未经认证的 CONNECT。
- CDN 缓存键纳入认证与内容协商边界,避免私有数据泄漏。
- WebSocket 在握手时验证 Origin、认证与授权;连接建立后每条业务消息仍需授权。
- RPC 重试必须配合幂等和重试预算,避免放大故障。
- 对 Host、path、转发字段和协议转换做规范化,防范请求走私与路由绕过。
- 日志中脱敏 Authorization、Cookie、Token、查询参数和业务负载。
十七、实现与平台差异
- 云负载均衡的健康检查、调度算法、源地址保留、跨区、连接迁移、配额和计费均属厂商实现,必须查对应产品版本文档。
- Nginx 开源版、Nginx Plus、HAProxy、Envoy、Traefik 和云网关能力不同,尤其是主动健康检查、动态发现和高级重试。
- HTTP/2 WebSocket 需要 RFC 8441,HTTP/3 WebSocket 需要 RFC 9220;端到端每一跳都要支持。
- gRPC 经不理解 HTTP/2 trailers 的代理时可能出现状态丢失。
- WebSocket、SSE 和流式 RPC 的默认空闲超时在不同代理中差异很大。
- 四层负载均衡是否保留源地址、是否使用连接跟踪、回程路径要求均依赖转发模式。
十八、关联章节
- 前置:13 TCP 连接与状态机、16 HTTP、17 TLS
- 后续:19 DHCP、NAT 与连接跟踪、防火墙与访问控制、性能观测、分层故障排查
- 实验:20 统一实验项目
检索关键词
HTTP RPC 区别 gRPC HTTP/2 deadline retry WebSocket 握手 Sec-WebSocket-Accept WebSocket frame mask ping pong 正向代理 反向代理 API 网关 四层 七层 负载均衡 NAT DSR full proxy 健康检查 readiness draining 负载均衡算法 consistent hash least request CDN 缓存键 回源 purge Forwarded X-Forwarded-For 502 503 504 排障
权威来源
- RFC 6455: The WebSocket Protocol
- RFC 7239: Forwarded HTTP Extension
- RFC 8441: Bootstrapping WebSockets with HTTP/2
- RFC 9110: HTTP Semantics
- RFC 9113: HTTP/2
- RFC 9220: Bootstrapping WebSockets with HTTP/3
- gRPC Core Concepts
- 小林 coding《图解网络》目录(主题覆盖参考,协议结论以标准和官方文档为准)
本章于 2026-09-07 完成规范与主题核验。Docker/Nginx 实验因当前未执行而明确标注为预期结果;实际部署需以使用中的代理、云负载均衡和 CDN 版本文档及受控实验为准。
