React调用Python Pyramid API时出现CORS预请求错误
解决React调用Pyramid API的CORS预请求错误
问题背景
我有一个ReactJS构建的前端Web应用,调用Python Pyramid框架开发的API。本地测试时,前端部署在localhost:6543,Python应用部署在localhost:3000,调用API时出现CORS预请求错误。
前端请求代码
const onFinish = (values) => { fetch(`${baseUrl}login`, { method: "POST", mode: 'no-cors', headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "http://localhost:3000", }, body: JSON.stringify(values), });
Pyramid后端CORS配置代码
from pyramid.config import Configurator from invest_web.authentication.security import SecurityPolicy from pyramid.response import Response from pyramid.events import NewRequest from invest_web.models.models import User, Issuer def add_cors_headers_response_callback(event): def cors_headers(request, response): response.headers['Access-Control-Allow-Origin'] = '*' response.headers['Access-Control-Allow-Methods'] = 'POST,GET,DELETE,PUT,OPTIONS' response.headers['Access-Control-Allow-Headers'] = 'access-control-allow-origin,content-type' response.headers['Access-Control-Allow-Credentials'] = 'true' event.request.add_response_callback(cors_headers) def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ with Configurator(settings=settings) as config: config.include('pyramid_jinja2') config.set_security_policy( SecurityPolicy( secret=settings['invest_web.secret'] ), ) config.add_subscriber(add_cors_headers_response_callback, NewRequest) config.include('.routes') config.include('.models') config.scan() return config.make_wsgi_app()
错误截图

问题分析及修复方案
1. 前端请求修正
- 移除
mode: 'no-cors':该模式会让请求变为不透明类型,浏览器会屏蔽所有响应信息,直接导致CORS逻辑失效。 - 移除请求头中的
Access-Control-Allow-Origin:这是服务器返回的响应头,前端无需设置。
修改后的前端代码:
const onFinish = (values) => { fetch(`${baseUrl}login`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(values), }) .then(response => response.json()) .catch(error => console.error('请求错误:', error)); };
2. 后端CORS配置完善
当前后端仅添加了响应头,但未正确处理OPTIONS预请求(浏览器发送非简单请求前会先触发该请求),需补充相关逻辑:
from pyramid.config import Configurator from invest_web.authentication.security import SecurityPolicy from pyramid.response import Response from pyramid.events import NewRequest from invest_web.models.models import User, Issuer def add_cors_headers_response_callback(event): def cors_headers(request, response): # 动态匹配请求Origin,支持带凭证的CORS请求(*和凭证不能共存) origin = request.headers.get('Origin') response.headers['Access-Control-Allow-Origin'] = origin if origin else '*' response.headers['Access-Control-Allow-Methods'] = 'POST,GET,DELETE,PUT,OPTIONS' response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization' response.headers['Access-Control-Allow-Credentials'] = 'true' # 设置预请求缓存时长,减少重复OPTIONS请求 response.headers['Access-Control-Max-Age'] = '3600' event.request.add_response_callback(cors_headers) def options_response(request): # 专门处理OPTIONS预请求,返回200状态码 return Response(status=200) def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ with Configurator(settings=settings) as config: config.include('pyramid_jinja2') config.set_security_policy( SecurityPolicy( secret=settings['invest_web.secret'] ), ) config.add_subscriber(add_cors_headers_response_callback, NewRequest) # 给所有路由绑定OPTIONS请求处理 config.add_route('options', '*subpath', request_method='OPTIONS') config.add_view(options_response, route_name='options') config.include('.routes') config.include('.models') config.scan() return config.make_wsgi_app()
3. 关键注意事项
- 若前端需要携带凭证(如Cookie),
Access-Control-Allow-Origin不能设为*,必须指定具体的请求源(如上代码中动态获取)。 Access-Control-Allow-Headers需包含前端实际使用的请求头,比如如果用到Authorization也要加入列表。
内容的提问来源于stack exchange,提问作者user1050619
相关产品推荐
相关产品推荐

