From f5f8e74a924ec0fa21025c78583dcd248e6d33f0 Mon Sep 17 00:00:00 2001 From: hoelee Date: Wed, 28 Oct 2026 09:09:48 +0800 Subject: [PATCH] post: first-person voice pass on the 499 post (EN+ZH, no second person in body) --- ...hen-a-proxy-timeout-returns-html-instead-of-json.md | 10 +++++----- ...hen-a-proxy-timeout-returns-html-instead-of-json.md | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/posts/when-a-proxy-timeout-returns-html-instead-of-json.md b/src/content/posts/when-a-proxy-timeout-returns-html-instead-of-json.md index d719435..3b4ff9f 100644 --- a/src/content/posts/when-a-proxy-timeout-returns-html-instead-of-json.md +++ b/src/content/posts/when-a-proxy-timeout-returns-html-instead-of-json.md @@ -266,7 +266,7 @@ rewrite did not quietly drop a control. 1. **A dashboard endpoint is not a query interface.** It is the most frequently called and least cached surface in an admin UI. Anything O(n) over user data belongs in a background job with a publish step, not in the GET that a browser polls on focus. -2. **Your timeout budget is the smallest hop, not the sum.** Four proxies each "allowing" 120 s do +2. **The timeout budget is the smallest hop, not the sum.** Four proxies each "allowing" 120 s do not add up; the request dies at whichever clock expires first, and the application cannot see any of them. The application-side budget has to be an order of magnitude under the smallest one. 3. **`499` deserves an alert.** It is the only signal that reports "the caller gave up", and it @@ -275,8 +275,8 @@ rewrite did not quietly drop a control. 4. **Never trust `res.json()` on a proxied route.** Read text, keep the status, keep the first line. The error message is the only artefact the next engineer will have. 5. **Stale-while-revalidate beats a bigger number.** Raising a timeout moves the wall; decoupling - compute from read removes it — and it removes it for the worst case you have not measured yet - (2,507 s here), not just the one you did (13.6 s). + compute from read removes it — and it removes it for the worst case I have not measured yet + (2,507 s here), not just the one I did (13.6 s). --- @@ -294,5 +294,5 @@ rewrite did not quietly drop a control. `HTTP 503 · …` and the investigation starts at the right layer. The single most useful line in this whole exercise was the one that lied: `Unexpected token '<'`. -An HTML error page handed to a JSON caller is not a syntax error — it is a proxy telling you, in the -only language it has, that it stopped waiting before your code ever woke up. +An HTML error page handed to a JSON caller is not a syntax error — it is a proxy telling me, in the +only language it has, that it stopped waiting before my code ever woke up. diff --git a/src/content/posts/zh/when-a-proxy-timeout-returns-html-instead-of-json.md b/src/content/posts/zh/when-a-proxy-timeout-returns-html-instead-of-json.md index 1d4abdd..9d3ff35 100644 --- a/src/content/posts/zh/when-a-proxy-timeout-returns-html-instead-of-json.md +++ b/src/content/posts/zh/when-a-proxy-timeout-returns-html-instead-of-json.md @@ -219,7 +219,7 @@ if (data.refreshing) { autoRetryTimer = setTimeout(window.autoReload, 3000); } 2. **超时预算等于最小那一跳,不是各跳之和。** 四层反代各自「允许」120 秒并不叠加:请求死在最先到期的那个时钟上,而应用一个都看不见。应用侧的预算必须比最小的那个还低一个数量级。 3. **`499` 值得配一条告警。** 它是唯一一个表达「调用方放弃了」的信号,且天然绕开所有基于 5xx 的监控。从访问日志抓单条路径上 499 与 200 的比值,几乎零成本覆盖这一整类故障。 4. **在反代后面永远不要信 `res.json()`。** 先读文本,留下状态码,留下第一行。下一个接手的人手里只有这条错误信息。 -5. **stale-while-revalidate 优于一个更大的数字。** 抬高超时只是把墙往后推;把计算与读拆开才是把墙拆掉——而且拆掉的是你还没量到的那个最坏值(这里的 2507 秒),不只是量到的那个(13.6 秒)。 +5. **stale-while-revalidate 优于一个更大的数字。** 抬高超时只是把墙往后推;把计算与读拆开才是把墙拆掉——而且拆掉的是我还没量到的那个最坏值(这里的 2507 秒),不只是量到的那个(13.6 秒)。 --- @@ -230,4 +230,4 @@ if (data.refreshing) { autoRetryTimer = setTimeout(window.autoReload, 3000); } - **正确性保留而非掩盖。** 撰写时的计数:341 篇笔记、1 个缺封面、47 篇待生成朗读——同一个计算,只是搬了位置。 - **故障再也无法伪装。** 任何一跳再次中断,卡片会打印 `HTTP 503 · …`,排查从正确的层级开始。 -整件事里最有用的一行,恰恰是那行说谎的 `Unexpected token '<'`。把 HTML 错误页递给一个 JSON 调用方,不是语法错误——那是反代用它唯一会说的语言在告诉你:你的代码还没醒,它就已经不等了。 +整件事里最有用的一行,恰恰是那行说谎的 `Unexpected token '<'`。把 HTML 错误页递给一个 JSON 调用方,不是语法错误——那是反代用它唯一会说的语言在告诉我:我的代码还没醒,它就已经不等了。