调用带CORS与auth=user的Odoo端点遇CORS重定向错误求助
问题:Odoo带auth=user的端点触发CORS预请求重定向错误
我需要调用一个配置了CORS和auth='user'的Odoo端点,但始终收到CORS错误,以下是相关配置和代码:
已配置的目标端点
@http.route('/endpoint', type='json', cors='http://127.0.0.1:5173', auth='user', csrf=False, methods=['OPTIONS', 'POST']) def endpoint(self): return {'test'}
Axios调用代码
axios.post('http://127.0.0.1:8069/endpoint', { jsonrpc: "2.0", params: {}, }, { headers: {"Content-Type": "application/json"}, withCredentials: true, }) .then(content => { console.log(content.data) }) .catch(error => alert(JSON.stringify(error)))
收到的错误信息
Access to XMLHttpRequest at 'http://127.0.0.1:8069/endpoint' from origin 'http://127.0.0.1:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
已正常工作的登录接口
登录接口配置和调用都没问题,代码如下:
登录端点代码
@http.route('/login', type='json', cors='http://127.0.0.1:5173', auth='none', csrf=False, methods=['OPTIONS', 'POST']) def login(self, db, login, password): http.request.session.authenticate(db, login, password) return http.request.env['ir.http'].session_info()
登录接口Axios调用
axios.post('http://127.0.0.1:8069/login', { jsonrpc: "2.0", params: { db: "db_name", login: email, password: password }, }, { headers: {"Content-Type": "application/json"}, withCredentials: true, }) .then(content => { console.log(content.data) }) .catch(error => alert(JSON.stringify(error)))
解决方案
问题根源
当端点设置auth='user'时,Odoo会拦截未携带有效会话的请求,自动重定向到登录页面。但浏览器发送的OPTIONS预请求不会携带会话凭证(即使开启withCredentials: true),导致预请求被重定向,而CORS规则明确禁止预请求被重定向,因此触发错误。
修复方案:拆分OPTIONS与POST请求的认证规则
将OPTIONS请求单独配置为auth='none',确保预请求能正常通过,同时保持POST请求的用户认证要求。
方案1:拆分两个路由
# 处理POST请求,保持用户认证 @http.route('/endpoint', type='json', cors='http://127.0.0.1:5173', auth='user', csrf=False, methods=['POST']) def endpoint(self): return {'test': 'success'} # 单独处理OPTIONS预请求,无需认证 @http.route('/endpoint', type='http', cors='http://127.0.0.1:5173', auth='none', csrf=False, methods=['OPTIONS']) def endpoint_options(self): headers = { 'Access-Control-Allow-Origin': 'http://127.0.0.1:5173', 'Access-Control-Allow-Methods': 'POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Allow-Credentials': 'true' } return request.make_response('', headers=headers)
方案2:在同一个路由中处理两种请求
@http.route('/endpoint', type='json', cors='http://127.0.0.1:5173', auth='none', csrf=False, methods=['OPTIONS', 'POST']) def endpoint(self): # 处理OPTIONS预请求 if request.method == 'OPTIONS': headers = { 'Access-Control-Allow-Origin': 'http://127.0.0.1:5173', 'Access-Control-Allow-Methods': 'POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Allow-Credentials': 'true' } return request.make_response('', headers=headers) # 手动验证用户会话,替代auth='user'的自动校验 if not request.session.uid: raise AccessDenied() # 业务逻辑处理 return {'test': 'success'}
注意事项
- 确保CORS头中的
Access-Control-Allow-Origin与前端域名完全一致(包括端口) - 必须返回
Access-Control-Allow-Credentials: true,配合前端的withCredentials: true传递会话凭证
内容的提问来源于stack exchange,提问作者Jan
相关产品推荐
相关产品推荐

