必须用CORSMiddleware显式注册,且allow_origins不能为["*"]当allow_credentials=True时;否则浏览器静默拒绝带Cookie或Authorization头的请求,因预检(OPTIONS)阶段失败且不返回CORS响应头。

直接结论:必须用 CORSMiddleware 显式注册,且 allow_origins 不能填 ["*"] 当 allow_credentials=True 时——否则浏览器静默拒绝带 Cookie 或 Authorization 头的请求。
为什么加了中间件还是报 CORS 错误?
常见现象是前端控制台报 Access to fetch at 'http://localhost:8000/api' from origin 'http://localhost:3000' has been blocked by CORS policy,但后端日志里根本没收到请求。
这说明浏览器卡在了预检(OPTIONS)阶段。根本原因通常是:
-
allow_origins写成了["*"],但同时设了allow_credentials=True—— FastAPI 会直接忽略该中间件配置,不返回任何 CORS 头 - 前端发的是带
Authorization头或Content-Type: application/json的POST,触发预检,但allow_headers没包含"Authorization"或没放开"Content-Type" - 源写错了:比如前端是
http://localhost:3000,你配了https://localhost:3000(协议不匹配)或漏了端口
CORSMiddleware 必须传哪些参数?
最小可用配置取决于你的前端是否需要传凭证(如登录态 Cookie、Bearer Token)。不传 allow_origins 就等于没开 CORS;其他参数都有默认值,但默认值往往不够用。
生产环境推荐显式声明:
-
allow_origins=["https://your-frontend.com", "https://www.your-frontend.com"]—— 不要用["*"],尤其当涉及登录态时 -
allow_credentials=True—— 只有需要读写 Cookie 或发Authorization头才设为True -
allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"]——OPTIONS必须显式列出,否则预检失败 -
allow_headers=["Content-Type", "Authorization", "X-Requested-With"]—— 至少包含前端实际发送的头,["*"]在生产中不被允许(Starlette 会报错)
开发环境怎么快速调试不踩坑?
本地开发时前端常跑在 http://localhost:3000,后端在 http://localhost:8000,这是两个不同源(端口不同),必须配全。
安全又省事的开发配置是:
-
allow_origins=["http://localhost:3000"]—— 精确匹配,避免将来上线漏改 -
allow_credentials=True—— 开发时一般要测登录态,别省这行 -
allow_methods=["*"]—— 开发期方法多变,用通配比手动追加更稳 -
allow_headers=["*"]—— Starlette 允许开发期用["*"],只要allow_credentials=False或没启用凭证
预检缓存怎么减少 OPTIONS 频率?
每次非简单请求(如 PUT、带 Authorization 头的 POST)都会先发一次 OPTIONS,影响性能。设置 max_age 能让浏览器缓存预检结果:
-
max_age=86400表示缓存 24 小时,期间同源同方法同头的请求不再预检 - 注意:这个值只对预检有效,不影响实际请求的响应头
- 若前端频繁变更请求头或方法,
max_age设太高反而导致旧策略残留
真正容易被忽略的是:CORS 的最终裁定权在浏览器,服务端只是“声明意愿”。哪怕配置全对,只要 Origin 字符串和前端发起请求时的协议、域名、端口三者有一处不完全一致,就失败——连日志都不会进 FastAPI。


















