Flask配置Swagger UI遇跨域(CORS)问题,求解决方案
问题描述
我在Python中用Flask配置了Swagger UI,Swagger里的多个端点需要调用非本地服务器,但每次调用都触发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.
已尝试的方案:
- 使用
flask_cors库全局配置CORS - 自定义
flask_cors的resources和allow_headers参数 - 分别用HTTP/HTTPS启动Flask
- 查阅大量资料但无效
目前只能通过关闭Chrome安全模式临时开发:chrome.exe --user-data-dir="C:/Chrome dev session" --disable-web-security,且Postman可正常调用所有端点。
问题根源
CORS错误的核心不在你的Flask/Swagger服务,而在你要调用的外部目标服务器。浏览器的CORS策略要求跨域请求的响应必须携带Access-Control-Allow-Origin头,而你调用的外部服务器未返回该头,因此浏览器拦截了响应。Postman不受浏览器CORS规则限制,所以可以正常调用。
解决方案
方案1:Flask反向代理(推荐无外部服务器权限场景)
通过Flask做一层代理,让Swagger的请求先发给同域的Flask服务,再由Flask转发到外部端点。这样浏览器只和同域服务交互,不会触发CORS检查。
示例代码:
from flask import Flask, request import requests from flask_cors import CORS from flask_restx import Api # 适配flask-restx的Swagger配置 app = Flask(__name__) api = Api(app) CORS(app) # 代理外部服务的通用路由 @app.route('/proxy/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']) def proxy_request(path): # 替换为实际的外部服务器基础URL external_base_url = "https://XXXXXXXXXXXXX.XX/" target_url = f"{external_base_url}{path}" # 转发请求头(排除Host避免冲突) forward_headers = {k: v for k, v in request.headers.items() if k.lower() != 'host'} # 发送请求到外部服务器 response = requests.request( method=request.method, url=target_url, headers=forward_headers, data=request.get_data(), params=request.args, allow_redirects=True ) # 处理响应头,排除浏览器不允许跨域设置的头 excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection'] response_headers = [ (k, v) for k, v in response.raw.headers.items() if k.lower() not in excluded_headers ] return (response.content, response.status_code, response_headers) # 原有的Swagger API配置... if __name__ == '__main__': # 若用HTTPS,可使用adhoc临时证书或自有证书 app.run(ssl_context='adhoc', port=40)
修改Swagger端点地址:将原来的https://XXXXXXXXXXXXX.XX/xxx改为/proxy/xxx,让请求先经过Flask代理。
方案2:修改外部服务器CORS配置(适用于有权限修改外部服务场景)
如果你能控制外部服务器,需要:
- 在外部服务器的响应中添加
Access-Control-Allow-Origin头,值为你的Swagger服务Origin(即https://XX.XX.XX.X:40),生产环境不建议用* - 确保外部服务器正确处理OPTIONS预请求,返回
Access-Control-Allow-Methods、Access-Control-Allow-Headers等必要头
方案3:开发环境临时方案
除了你当前使用的Chrome不安全模式,还可以:
- 使用CORS浏览器插件(如CORS Unblock)临时绕过检查,仅用于开发
- 使用
curl或Python脚本测试接口,避开浏览器CORS限制
内容的提问来源于stack exchange,提问作者Ankit Bijlwan

