Flask-CORS必须在所有路由注册前初始化,否则不生效;origins="*"与supports_credentials=True互斥;预检请求需正确响应OPTIONS;Nginx需透传CORS响应头。

CORS不是“开了就能用”,而是必须让 Flask-CORS 真正接管到你发出响应的那条路由——否则浏览器收不到 Access-Control-Allow-Origin,前端就必然报错。
为什么 CORS(app) 写了却没生效
最常见原因是它被放在了所有 @app.route 之后,或者塞进了 if __name__ == '__main__': 里。Flask-CORS 只会对它执行之后注册的路由生效;而你的视图函数早已注册完毕,插件根本没管到它们。
- 确保
CORS(app)紧跟在app = Flask(__name__)后面,且在任何@app.route之前 - 如果用了蓝图(
Blueprint),CORS(app)不会自动覆盖蓝图内的视图,必须显式调用CORS(my_blueprint)或对单个函数加@cross_origin() - 开发时
debug=True可能触发多进程热重载,改完配置只加载进一个进程,另一个旧进程还在跑——重启整个服务才能确认是否真生效
生产环境 origins 配置踩坑点
origins="*" 和 supports_credentials=True 是互斥的。只要前端带了 credentials: 'include'(比如发 cookie 或 Authorization 头),浏览器就会直接拒绝响应,连错误细节都不给全,控制台只显示模糊的 “CORS error”。
- 开发阶段用明确列表:
origins=["http://localhost:3000", "http://127.0.0.1:3000"] - 生产环境必须写完整 HTTPS 域名,不含端口:
origins=["https://myapp.com", "https://admin.myapp.com"] - 避免正则匹配(如
r"https?://(localhost|myapp)\.com(:\d+)?")——转义易错、调试困难,上线前先用静态列表验证通路
POST/PUT/DELETE 卡在 OPTIONS 预检
Axios 或 fetch 发 Content-Type: application/json 时,浏览器强制走预检(OPTIONS 请求)。如果后端没正确响应这个 OPTIONS,真实请求根本不会发出。
调用 Cutout.Pro 视觉处理 API 进行背景移除、人像抠图和照片增强,支持文件上传与图片 URL 输入。
立即学习“Python免费学习笔记(深入)”;
- 别手动写
@app.route("/xxx", methods=["OPTIONS"])—— 这会覆盖flask-cors自带的处理逻辑 - 全局配置要显式包含
OPTIONS:CORS(app, methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"]) - 用
@cross_origin装饰器时也得传methods参数,例如:@cross_origin(origins=["http://localhost:3000"], methods=["POST", "OPTIONS"]) - 打开浏览器 Network 面板,确认第一个请求是 OPTIONS、状态码为 200、响应头里有
Access-Control-Allow-Methods和Access-Control-Allow-Headers
Nginx/uWSGI 部署后 CORS 失效
很多情况下本地跑得好好的,一上服务器就跨域失败——大概率是 Nginx 把 Access-Control-Allow-Origin 等响应头吞掉了,默认不透传自定义头。
- 在 Nginx 配置中加:
add_header 'Access-Control-Allow-Origin' '$sent_http_access_control_allow_origin' always;(或直接写死值,但需与后端一致) - 确保
add_header指令在location块内,且未被其他add_header覆盖 - 检查 uWSGI 是否启用了
disable-websockets或自定义中间件,它们可能清空或覆盖响应头
真正容易被忽略的是:CORS 配置是否实际作用到了那个请求路径上——它可能被蓝图隔离、被 Nginx 截断、被多进程绕过,甚至被你自己写的 before_request 中间件悄悄抹掉。不要只看代码有没有写,要看浏览器 Network 里那个响应头到底有没有发出去。

















