FastAPI CORS预检失败主因是CORSMiddleware注册顺序错误且allow_methods未显式包含"OPTIONS":必须在所有路由定义前注册中间件,否则OPTIONS请求匹配不到路由而返回405/404;同时allow_methods需明确列出"OPTIONS"以确保预检被正确响应。

CORS中间件没注册对位置,OPTIONS请求根本进不到它手里——这是90%的预检失败根源。
为什么OPTIONS请求返回405或404
FastAPI不会自动响应OPTIONS请求,除非CORSMiddleware已加载且能拦截到它。如果中间件注册在路由之后,请求会先匹配路由表;而你通常没写@app.options("/path"),所以直接报405(Method Not Allowed)或404(No route matched)。
- 中间件注册顺序必须在所有
app.get()、app.post()等路由定义之前 - 不能放在
app = FastAPI()之后、但又在app.add_middleware(...)之前加自定义中间件——那中间件可能提前终止请求 - 检查日志:如果看到
OPTIONS /api/login触发了405 Method Not Allowed,基本可断定CORSMiddleware没生效
allow_methods必须显式包含"OPTIONS"
CORSMiddleware默认只放行GET和POST,即使你写了allow_methods=["*"],它内部仍需明确知道要响应OPTIONS——因为预检本身就是OPTIONS请求,不是“被允许的方法”,而是“用来协商方法的机制”。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 务必在
allow_methods里加上"OPTIONS",例如:allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"] -
["*"]在大多数FastAPI版本中会自动展开,但某些旧版本或自定义配置下可能不包含OPTIONS,显式写出来最稳 - 如果后端只提供
GET接口,但前端发了带Authorization头的GET,仍会触发预检——此时allow_methods哪怕只写["GET"]也不够,必须含"OPTIONS"
allow_origins不能用"*" + allow_credentials=True
当你在前端用了credentials: "include"(比如带cookie或token),而后端配了allow_credentials=True,但allow_origins=["*"],浏览器会直接拒绝整个预检响应——连Access-Control-Allow-Origin都不会认。
- 必须把
allow_origins设为具体列表,例如:["http://localhost:3000", "https://myapp.com"] - 开发时可加
allow_origin_regex=r"http://localhost:\d+"临时放宽,但别上生产 - 注意协议、端口、路径都要完全匹配;
http://localhost:3000≠http://127.0.0.1:3000
预检缓存没配导致高频OPTIONS请求
每次非简单请求前都发一次OPTIONS,不仅慢,还容易被限流。FastAPI支持用max_age让浏览器缓存预检结果。
- 加
max_age=600(单位秒),浏览器会在10分钟内复用上次预检响应,不再重复发OPTIONS - 这个值不能无限大;太长会导致前端改了
Content-Type或头字段后,后端CORS配置已更新,但浏览器还在用旧缓存 - 配合
expose_headers可让前端读取自定义响应头,但和预检失败无关,属于进阶优化
最容易被忽略的是中间件顺序和OPTIONS是否在allow_methods里——这两点错一个,预检就卡死在第一步,后面所有配置都白搭。

















