为什么 Azure Front Door 让我的 Next.js 应用加载耗时 90 秒(以及我如何修复)
Source: Dev.to
请提供您想要翻译的完整文本(文章正文),我将把它翻译成简体中文并保留原有的格式、Markdown 语法以及技术术语。谢谢!
Problem
我们在 Azure Front Door Premium 私有链接后面,将 Next.js 应用部署到 Azure Container Apps。
一切都是标准配置——没有任何特殊之处。
部署后,每个页面的加载时间约为 90 秒。
- HTML 文档能够正常加载。
- API 路由响应快速。
- 每个 JavaScript 块 正好卡住 90 秒,随后浏览器抛出
ERR_HTTP2_PROTOCOL_ERROR(底层 HTTP/2 流因INTERNAL_ERROR (err 2)而终止)。
注意: 此故障影响了 所有 块,而不仅仅是一部分。
环境
| 组件 | 详情 |
|---|---|
| App | Next.js 16 on Azure Container Apps(内部环境,Private Link) |
| CDN/WAF | Azure Front Door Premium |
| Routes | • API – /api/* • 静态资源 – /_next/static/* • 全匹配 – /* |
| Next.js config | compress: true(默认) |
| Health probes | 100 % 健康;小响应正常 |
SSR 页面 (/sign‑in, 78 KB) | 通过全匹配路由在约 300 ms 内加载 – 静态资源交付是问题所在 |
重现问题
相同的 JS 块 – 有无 Accept‑Encoding 的情况
# Without gzip — 303 ms, full response
curl -s -w "Total: %{time_total}s\n" -o /dev/null \
"https://my-fd-endpoint.azurefd.net/_next/static/chunks/app.js"
#=> Total: 0.303414s
# With gzip — 90 seconds, incomplete, HTTP/2 stream error
curl -s -w "Total: %{time_total}s\n" -o /dev/null \
-H "Accept-Encoding: gzip" \
"https://my-fd-endpoint.azurefd.net/_next/static/chunks/app.js"
#=> Total: 90.245256s
两个请求都命中 相同的文件、相同的路由、相同的源。
唯一的区别是:客户端请求 gzip 压缩。
响应头(gzip 请求)
HTTP/2 200
content-type: application/javascript; charset=UTF-8
content-length: 112049
cache-control: public, max-age=31536000, immutable
content-encoding: gzip
vary: Accept-Encoding
x-cache: TCP_MISS
x-azure-ref: 20260220T195031Z-157f99bd8b842q87hC1CPH...
content-length: 112049带有content-encoding: gzip。curl只报告收到 8,527 字节,随后 HTTP/2 流因INTERNAL_ERROR (err 2)而终止。
SSR 页面(/sign‑in)– 正常工作
HTTP/2 200
content-type: text/html; charset=utf-8
vary: rsc, next-router-state-tree, next-router-prefetch, ...
cache-control: private, no-cache, no-store, max-age=0, must-revalidate
x-cache: CONFIG_NOCACHE
- 没有
content-encoding。 - 没有
content-length(分块传输)。
源站 不对 SSR 响应进行 gzip,即使客户端请求也是如此。这就是 SSR 页面正常而静态块失败的原因。
我们尝试了
| 尝试 | 更改 | 结果 |
|---|---|---|
| 1 | 禁用 Front Door 压缩 (compression_enabled = false) | 仍然出错 – 证明问题不是双重压缩。 |
| 2 | 完全移除缓存块 | 仍然出错 – 缓存不是原因。 |
| 3 | 将转发协议切换为 HttpOnly(通过 Private Link 的 TLS) | 仍然出错 – TLS 开销不是问题。 |
结论: Front Door 无法正确转发已 gzip 压缩的源站响应;它会在恰好 90 秒后停止并终止连接,这与 Front Door 不可配置的 HTTP keep‑alive 空闲超时相匹配。
这种行为 并非 Private Link 特有。Microsoft 有一篇健康建议,描述了在 PoP 之间收紧 HTTP 合规性后出现的相同故障。他们的 Q&A 线程(一个,两个)指向相同的解决方案:禁用源站压缩。
修复
- 在源端禁用压缩。
- 让 Front Door 在边缘进行压缩。
示例:Next.js
// next.config.js
const nextConfig = {
compress: false, // Front Door will compress at the edge
// …
};
module.exports = nextConfig;
示例:Front Door 路由配置(Terraform)
resource "azurerm_cdn_frontdoor_route" "static" {
# …
cache {
query_string_caching_behavior = "UseQueryString"
compression_enabled = true
content_types_to_compress = [
"text/html",
"text/css",
"text/javascript",
"application/javascript",
"application/x-javascript",
"application/json",
"image/svg+xml",
"font/woff2",
]
}
}
其他平台
| 平台 | 如何禁用压缩 |
|---|---|
| Express | 移除/禁用 compression 中间件。 |
| Azure App Service | 设置 WEBSITES_DISABLE_CONTENT_COMPRESSION=1。 |
| Nginx (behind AFD) | 关闭 gzip(gzip off;)。 |
快速诊断
对同一资源运行以下两个 curl 命令:
# 1️⃣ Without compression
curl -s -w "TTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
-o /dev/null "https://your-fd-endpoint.azurefd.net/your-asset.js"
# 2️⃣ With compression
curl -s -w "TTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
-o /dev/null -H "Accept-Encoding: gzip" \
"https://your-fd-endpoint.azurefd.net/your-asset.js"
如果第一个在毫秒内完成,而第二个卡住约 90 秒,则说明您遇到了此问题。
保存错误响应中的 x-azure-ref 头部——如果向 Microsoft 提交支持工单时会需要它。
预期的健康响应(修复后)
HTTP/2 200
content-type: application/javascript; charset=UTF-8
content-length: 41182
cache-control: public, max-age=31536000, immutable
content-encoding: gzip
vary: Accept-Encoding
x-cache: TCP_HIT
x-azure-ref: …
现在,源站发送未压缩的数据,Front Door 只压缩一次,资产会立即交付。
immutable
x-cache: TCP_HIT
没有来自源站的 content‑encoding。Front Door 在毫秒级从缓存中提供。若看到 x-cache: TCP_HIT 且没有卡顿,说明一切正常。
相关资源
- 故障排除文件压缩 - Azure Front Door(Microsoft Learn)
- 无法使用 Accept-Encoding: gzip 完成资源下载(Microsoft Q&A)
- Azure Front Door 静态资源的 HTTP/2 协议错误(Microsoft Q&A)
- Envoy + Azure CDN gzip 范围请求问题(GitHub)
- Azure CDN 的 HTTP2_PROTOCOL_ERROR(Microsoft Q&A)
- Azure Front Door FAQ - 超时(Microsoft Learn)
- 通过压缩文件提升性能(Microsoft Learn)