Flask Swagger CORS 问题解决指南
2025-02-04 11:00:45
Flask Swagger中的CORS问题处理
CORS(Cross-Origin Resource Sharing,跨域资源共享)是在Web开发中常见的安全机制,它限制了运行在一个域中的网页脚本访问另一个域中的资源。当你在Flask中集成Swagger UI时,并且你的API服务与Swagger UI不在同一个域下,CORS问题很可能出现。 这会导致浏览器拒绝跨域请求,即使服务器返回了数据。
常见CORS错误信息:
Access to fetch at 'https://XXXXXXXXXXXXX.XX/' from origin 'https://XX.XX.XX.X:40' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
产生CORS问题的根本原因是浏览器的同源策略。 简单来说,同源策略要求Web应用只能访问与其来源(协议、域名、端口)相同的资源。 如果请求的资源与当前页面的来源不同,浏览器就会阻止这个请求。
以下几种方法可以用来解决 Flask Swagger 中的 CORS 问题。
1. 使用 Flask-CORS 扩展
flask-cors
是一个简单且强大的Flask扩展,它能轻松地处理CORS相关的HTTP头部设置。这是最常用、推荐的解决方案。
原理: flask-cors
为 Flask 应用自动添加响应头 Access-Control-Allow-Origin
,告诉浏览器允许特定的域进行跨域请求。
操作步骤:
-
安装 Flask-CORS:
pip install flask-cors
-
初始化 CORS:
在 Flask 应用初始化时,将CORS应用于整个app或特定路由。以下展示几种常见的用法:
- 允许所有来源:
from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app) # 允许来自所有域的请求 @app.route("/") def hello(): return "Hello World!" if __name__ == '__main__': app.run(debug=True)
- 允许特定来源:
from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app, resources={r"/api/*": {"origins": "https://example.com"}}) # 只允许来自example.com域对/api/下的所有路径的请求 @app.route("/api/resource") def resource(): return "This is a protected resource!" if __name__ == '__main__': app.run(debug=True)
- 更细粒度的配置(允许特定methods和headers):
from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app, resources={r"/api/*": {"origins": "https://example.com", "methods": ["GET", "POST"], "allow_headers": ["Content-Type", "Authorization"]}}) @app.route("/api/resource", methods=["GET", "POST"]) def resource(): return "This is a protected resource!" if __name__ == '__main__': app.run(debug=True)
配置说明:
origins
:指定允许的来源域。可以使用通配符*
允许所有域,但不建议在生产环境中使用,因为存在安全风险。最好明确指定允许的域。methods
:允许的HTTP方法,如GET、POST、PUT、DELETE等。allow_headers
:允许客户端在请求中携带的自定义头部。 如果不设置,浏览器可能会阻止携带某些头部信息的请求。 常用的Content-Type
一般是需要的。Authorization
则用于携带token.
-
确保Swagger UI的URL在允许的来源中 。 如果Swagger UI运行在
https://my-swagger-ui.com
,你的Flask应用需要配置CORS(app, resources={r"/*": {"origins": "https://my-swagger-ui.com"}})
。
2. 手动添加响应头
虽然使用flask-cors
扩展通常更方便,但也可以手动设置CORS响应头。
原理: 拦截请求并在响应中添加相应的HTTP头信息,明确告知浏览器允许跨域请求。
操作步骤:
-
创建一个装饰器或中间件:
from flask import Flask, make_response app = Flask(__name__) @app.after_request def add_cors_headers(response): response.headers['Access-Control-Allow-Origin'] = '*' #不建议生产环境使用 *,需改为指定域名 response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization' response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE,OPTIONS' return response @app.route("/") def hello(): return "Hello World!" if __name__ == '__main__': app.run(debug=True)
或,也可以使用更严格的方式控制OPTIONS请求:
from flask import Flask, make_response, request app = Flask(__name__) @app.before_request def handle_preflight(): if request.method == "OPTIONS": res = make_response() res.headers['Access-Control-Allow-Origin'] = '*' #不建议生产环境使用 *,需改为指定域名 res.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization' res.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE,OPTIONS' return res @app.after_request def add_cors_headers(response): response.headers['Access-Control-Allow-Origin'] = '*' #不建议生产环境使用 *,需改为指定域名 return response @app.route("/") def hello(): return "Hello World!" if __name__ == '__main__': app.run(debug=True)
-
注册中间件或使用装饰器
-
与
flask-cors
一样,谨慎设置Access-Control-Allow-Origin
。 在生产环境中应避免使用*
,以防止潜在的安全风险。
安全建议
- 不要在生产环境中使用通配符
*
作为Access-Control-Allow-Origin
。 明确指定允许的域名。 - 只允许必要的HTTP方法和头部。 避免允许不安全的方法或未知的头部。
- 验证
Origin
头部。 在处理跨域请求时,始终验证Origin
头部,以确保请求来自可信的来源。
解决 CORS 问题需要理解其根本原因,并选择合适的解决方案。 flask-cors
扩展提供了一种便捷的方法来处理 CORS,但手动添加响应头也同样可行。 务必牢记安全最佳实践,防止潜在的安全风险。