From CORS multi-permission errors to Cloudflare cache hit issue
一次完整的 Nginx + FastAPI TTS 服务排错记录
最近为了保证Worder的英文朗读质量,我部署一个 TTS(Text-to-Speech)API接口微服务,并通过 Cloudflare 做加速缓存。一路踩坑的经历非常典型:
- CORS 报错
MultipleAllowOriginValues - Cloudflare 免费套餐下,页面规则/缓存规则无法缓存 API →
cf-cache-status: BYPASS - 本地缓存
x-cache: HIT,但 CDN 不命中 - blob URL 出现
206 Partial Content
这篇文章记录完整排查过程和最终可行方案。
1. 背景
- 前端站点:
https://worder.me - TTS API:
https://worder.me/api/tts?text=xxx&lang=en&format=mp3 - 后端:Python FastAPI
- 前置:Nginx 反向代理 + Cloudflare CDN
目标:让 TTS 结果在 Cloudflare 全站缓存(HIT),减轻服务器压力。
2. CORS 报错 —— MultipleAllowOriginValues
前端播放音频报错:
Cross-Origin Resource Sharing error: MultipleAllowOriginValues
原因
- FastAPI 添加了 CORS 中间件
- Nginx 同时设置了 CORS 响应头
浏览器收到两个 Access-Control-Allow-Origin,报错。
解决
- FastAPI 注释掉 CORS 中间件
- Nginx 统一管理 CORS:
location /api/ {
set $cors_origin "";
if ($http_origin ~* ^https://(www\.)?worder\.me$) {
set $cors_origin $http_origin;
}
add_header Access-Control-Allow-Origin $cors_origin always;
add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type" always;
}
✅ CORS 问题解决。
3. 免费套餐缓存规则 / 页面规则无法解决 BYPASS
尝试:
- 页面规则:
*worder.me/api/tts* - 缓存规则:URI 路径开头
/api/tts
但是 Cloudflare 免费套餐的 动态 API + query 参数 仍然显示:
cf-cache-status: BYPASS
原因:
- 免费套餐无法自定义 Cache Key
- Cloudflare 默认不缓存带 query 的动态请求
- 页面规则 / 缓存规则只能缓存静态文件或完全匹配规则
所以必须使用 Worker 强制缓存。
4. Worker 强制缓存解决方案
下面是我实际使用的 Worker 代码:
export default {
async fetch(request) {
const url = new URL(request.url);
// 只处理 TTS API
if (!url.pathname.startsWith('/api/tts')) {
return fetch(request);
}
// 转发到源站
const response = await fetch(url.toString(), {
method: request.method,
headers: request.headers,
cf: {
cacheEverything: true, // ← 关键:强制 Cloudflare 缓存非静态内容
cacheTtl: 2592000 // ← 缓存 30 天
}
});
// 创建新响应,移除 Set-Cookie
const newHeaders = new Headers(response.headers);
newHeaders.delete('Set-Cookie');
// 统一返回缓存头
newHeaders.set('Cache-Control', 'public, max-age=2592000, immutable');
return new Response(response.body, {
status: response.status,
headers: newHeaders
});
}
}
说明
cacheEverything: true→ 即使是动态 API 也会缓存cacheTtl: 2592000→ 缓存 30 天- 删除
Set-Cookie→ 防止 Cloudflare 拒绝缓存 - 返回
Cache-Control→ 告诉浏览器和 CDN 这是可缓存内容
✅ 使用 Worker 后,cf-cache-status: HIT 正常命中。
5. 验证缓存效果
第一次请求:
cf-cache-status: MISS
第二次请求:
cf-cache-status: HIT 🎉
浏览器端播放正常,TTS 服务器压力大幅下降。
6. blob URL + 206 正常现象
浏览器将音频流转成 blob,206 Partial Content = 支持 Range 请求,可拖动播放,与缓存无关。
7. 总结关键点
- CORS 报错 → Nginx + FastAPI 双重设置,保留一个
- 免费套餐缓存规则/页面规则 → 动态 API 仍 BYPASS
- Worker 强制缓存 →
cacheEverything+cacheTtl+Cache-Control - 删除 Set-Cookie → 避免缓存被拒
- blob + 206 → 正常现象
🎉 最终效果
- CORS OK
- Cloudflare HIT 成功
- TTS 服务压力降低
- 全球 CDN 加速
- 浏览器播放顺畅