Flask默认不支持CORS,需用flask-cors插件;开发可限定路径开启,生产必须显式指定origins且禁用*;推荐装饰器精准控制路由,避免全局配置暴露敏感接口,禁用手动设置CORS头,Nginx与Flask-CORS不可共存。

Flask 默认不处理 CORS,直接返回 403 或静默失败
浏览器发起跨域请求时,如果后端没返回 Access-Control-Allow-Origin 等响应头,预检请求(OPTIONS)会失败,或实际请求被拦截——你看到的可能是控制台报错 No 'Access-Control-Allow-Origin' header is present,也可能什么提示都没有,只是接口调不通。
Flask 本身不内置 CORS 支持,flask-cors 是最常用方案,但装上就用 CORS(app) 全局放开,等于把后门钥匙交出去。
- 开发环境可临时全开:
CORS(app, resources=r'/api/*')限定路径比CORS(app)更安全 - 生产环境必须显式声明允许的源:
origins=["https://your-frontend.com"],禁用*(尤其带credentials=True时无效) - 若前端用
fetch(..., { credentials: 'include' }),后端必须设supports_credentials=True,且origins不能为*
只对特定路由启用 CORS,避免暴露管理接口
用全局 CORS(app) 会让所有路由(包括 /admin、/health、/debug)都带上 CORS 头,增加攻击面。真实项目里,通常只有 /api/ 下的接口需要跨域。
推荐用装饰器方式精准控制:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
from flask_cors import cross_origin
@app.route('/api/users', methods=['GET'])
@cross_origin(origins=['https://app.example.com'], methods=['GET'])
def get_users():
return {'users': []}
- 装饰器比全局配置优先级高,可覆盖默认行为
-
methods参数建议显式列出,避免 OPTIONS 意外放行非预期方法 - 不要在
@cross_origin里写origins="*"+supports_credentials=True,这会导致浏览器直接拒绝请求
自定义响应头时,别覆盖 Flask-CORS 自动注入的头
有人会在视图里手动加 response.headers['Access-Control-Allow-Origin'] = ...,结果和 flask-cors 冲突,导致头重复或被覆盖——浏览器可能因头不一致而拒绝响应。
- 完全不用手动设 CORS 相关头,交给
flask-cors统一处理 - 如需额外头(比如
X-Request-ID),用after_request钩子,但避开Access-Control-前缀 - 调试时用
curl -I http://localhost:5000/api/test看实际返回头,确认没有重复或冲突
生产部署 Nginx 时,CORS 配置容易和 Flask-CORS 双重叠加
如果 Nginx 已配了 add_header Access-Control-Allow-Origin ...,又在 Flask 层开了 flask-cors,两者响应头会叠加,可能触发浏览器安全策略拒绝。
- 二选一:要么全由 Nginx 控制 CORS(适合静态资源+API 同域反代场景),要么全由 Flask 控制(微服务拆分后更可控)
- 若用 Nginx,务必删掉 Flask 中的
flask-cors相关代码,否则本地调试正常、上线就出问题 - Nginx 配置中,
add_header在location块内才生效;若放在server块,OPTIONS 请求可能没匹配到对应块而漏头
复杂点在于:预检请求(OPTIONS)是否由 Flask 处理,还是被 Nginx 直接返回 204——这决定了你该在哪层做响应头注入。多数人忽略这点,直到联调时发现 POST 接口始终过不了预检。

















