Flask CORS 失效主因是注册时机错误、凭据开关冲突、预检响应缺失或反向代理透传失败;CORS(app) 必须在路由注册前调用,带 credentials 时 origins 不能为 "*",需显式配置 methods 并确保 Nginx 透传响应头。

Flask 的 CORS 配置不是“装了插件就自动生效”,绝大多数失败都源于注册时机、凭据开关、预检响应或反向代理透传这四个环节中的某一个没对上。
为什么 CORS(app) 写了却没生效
最常见原因是执行顺序错误:把 CORS(app) 放在所有 @app.route 之后,或者塞进 if __name__ == '__main__': 块里。这时它只作用于后续动态注册的路由,而你的主接口早已注册完毕,完全不受影响。
-
CORS(app)必须在app实例创建后、任何路由注册前调用 - 若使用蓝图(
Blueprint),CORS(app)不会自动覆盖蓝图内视图,必须显式对蓝图注册:CORS(blueprint)或在每个路由上加@cross_origin - 开发时开启
debug=True可能触发多进程热重载,导致配置只加载到部分 worker 进程,重启后仍看到旧行为
带 Cookie 或 Authorization 时 origins="*" 一定报错
只要前端发请求时带了 credentials: true(比如 Axios 设置了 withCredentials: true),或后端启用了 supports_credentials=True,origins 就不能再设为 "*" —— 浏览器会直接拒绝响应,连 OPTIONS 都不放行。
- 开发阶段明确列出前端地址:
origins=["http://localhost:3000", "http://127.0.0.1:3000"] - 生产环境必须用完整 HTTPS 域名,不含端口:
origins=["https://myapp.com", "https://admin.myapp.com"] - Electron/WebView 场景可临时加
"file://",但仅限本地可信环境 - 正则匹配如
r"https?://(localhost|myapp)\.com(:\d+)?"容易漏转义,调试期建议先用静态列表确认通路
POST / PUT / JSON 请求发不出去?大概率卡在 OPTIONS 预检
Axios、fetch 发送 Content-Type: application/json 时,浏览器强制走预检(OPTIONS)。如果后端没正确响应这个 OPTIONS 请求,真实请求根本不会发出。
- 别手动写
@app.route("/xxx", methods=["OPTIONS"])—— 这会覆盖flask-cors自带的预检处理逻辑 - 确保初始化时包含
methods参数:CORS(app, methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"]) - 若用
@cross_origin装饰器,也得显式传methods:@cross_origin(origins=[...], methods=["POST", "OPTIONS"]) - 打开浏览器 Network 面板,看第一个请求是不是 OPTIONS、状态码是否为 200、响应头里有没有
Access-Control-Allow-Origin
Nginx 部署后 CORS 失效?多半是响应头被吞了
uWSGI/Gunicorn + Nginx 是常见组合,但 Nginx 默认不透传自定义响应头,Access-Control-Allow-Origin 等字段会被直接丢弃,浏览器收不到,CORS 就形同虚设。
- 在 Nginx 的
location块中加:add_header 'Access-Control-Allow-Origin' '$http_origin' always;(注意always,否则 4xx/5xx 响应不带) - 同时补全其他必要头:
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;和add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization' always; - 若需支持凭据,还需加:
add_header 'Access-Control-Allow-Credentials' 'true' always;
真正难调的从来不是“怎么配”,而是“哪个环节悄悄绕过了你的配置”——比如 Nginx 拦截了 OPTIONS、debug 模式下多个进程不同步、蓝图没单独挂 CORS、或者前端发了个带 credentials 的请求却还留着 origins="*"。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











