要让 proxy_cache_key 正确支持多语种站点的本地化缓存,关键是只保留并归一化真正影响响应内容的语言维度:用 map 提取主语言代码(如 zh、en),优先采用 url 路径或 cookie 中的显式语言标识,静态资源不加语言字段,ssr 页面和带语言参数的 api 则纳入稳定 $final_lang;最后通过响应头和日志验证缓存是否收敛。

要让 proxy_cache_key 正确支持多语种站点的本地化缓存,关键不是把所有语言相关字段全塞进去,而是只保留真正影响响应内容的语言维度,并做归一化处理——避免因 Accept-Language 格式差异、大小写、区域子标签(如 zh-CN vs zh-TW)或冗余参数导致同一语言内容生成多个缓存项。
只取主语言代码,忽略格式与子区域
浏览器发送的 Accept-Language 差异很大:en-US,en;q=0.9、zh-CN,zh;q=0.8、zh-TW、ZH-cn……这些本该指向同一套中文文案,却会生成不同 key。直接用 $http_accept_language 会导致严重缓存分裂。
推荐用 map 提取稳定主语言:
map $http_accept_language $lang {
~^zh "zh";
~^en "en";
~^ja "ja";
~^ko "ko";
~^fr "fr";
default "en";
}
这样,无论用户传的是 zh-CN、zh-TW 还是 ZH-hk,都统一映射为 "zh",确保中文内容共用一份缓存。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
结合路由或 Cookie 中的显式语言标识
有些站点通过 URL 路径(/en/about、/zh/about)或 Cookie(lang=ja)明确指定语言,这类信号比 Accept-Language 更权威、更可控。
优先级建议:URL path > Cookie > Accept-Language。例如:
- 从 $uri 提取路径前缀:
map $uri $route_lang { ~^/en/ "en"; ~^/zh/ "zh"; ~^/ja/ "ja"; default ""; } - 从 $http_cookie 提取 lang:
map $http_cookie $cookie_lang { ~lang=([^;]+) $1; default ""; } - 最终选用逻辑(在 server 或 location 块中):
set $final_lang $route_lang;;若为空,则 fallback:if ($final_lang = "") { set $final_lang $cookie_lang; };再 fallback 到 map 提取的 $lang
静态资源与 SSR 页面区别对待
缓存策略需按内容类型分层:
-
纯静态资源(JS/CSS/图片):语言不影响内容,key 中完全不需要 $lang —— 用
$scheme$host$uri即可 -
SSR 页面(如 Next.js、Nuxt 渲染的 HTML):语言决定模板、文案、日期格式等,必须纳入 key,但仅限稳定值:
proxy_cache_key "$scheme$host$uri|$final_lang"; - API 接口(如 /api/news):若返回带翻译的 JSON,且语言由 query 参数控制(?lang=ja),则提取 $arg_lang;若由 Header 控制,仍走 $lang map 归一化
验证是否真正收敛
改完 key 后,必须确认相同语言请求是否命中同一缓存:
- 加响应头:
add_header X-Cache-Lang $final_lang;和X-Cache-Status $upstream_cache_status; - 配置日志记录真实 key:
log_format cache_log '$time_local $upstream_cache_status "$request_uri" "$cache_key"'; - 用 curl 对比:
curl -H "Accept-Language: zh-CN" /about与curl -H "Accept-Language: ZH-tw" /about,观察是否均为 HIT 且 X-Cache-Lang 都是 "zh"










