Odoo12使用PHP/JS调用search_read接口返回session expired会话过期问题
Odoo12 调用接口返回会话过期问题解决方案
问题根因
你的代码存在3个核心问题导致会话验证失败:
- 请求头格式错误:你定义的
x-openerp-session_id :键名和冒号之间多了多余空格,导致服务端无法识别该请求头
- 请求头格式错误:你定义的
- Cookie手动拼接错误:仅手动传递sessionid字段,遗漏了Odoo会话依赖的其他Cookie属性,且容易出现格式错误
- 域名协议不一致:你登录接口请求用的是HTTPS协议,但Odoo返回的
web.base.url是HTTP协议,说明Odoo前端配置了反向代理HTTPS卸载,会话Cookie的作用域/secure属性匹配失败,导致后续请求会话无效
另外你提到Postman无需传session_id即可调用成功,是因为Postman之前存储了你登录Odoo后台的有效会话Cookie,清空Postman缓存和Cookie后即可复现错误
- 域名协议不一致:你登录接口请求用的是HTTPS协议,但Odoo返回的
修复方案
方案1:使用curl自动管理Cookie(最稳定)
无需手动拼接请求头和Cookie,让curl自动处理登录返回的会话Cookie,代码示例如下:
// 初始化curl,配置Cookie自动存储路径 $cookieFile = tempnam(sys_get_temp_dir(), 'odoo_cookie'); $ch = curl_init(); // 1. 调用登录接口 $loginData = [ 'json-rpc' => '2.0', 'method' => 'call', 'params' => [ 'db' => 'xxxx', 'login' => 'xxxx', 'password' => 'xxxx', 'context' => new stdClass() ], 'id' => 10 ]; $loginDataStr = json_encode($loginData); curl_setopt($ch, CURLOPT_URL, 'https://xxxxxxxxxxxxx/web/session/authenticate'); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_POSTFIELDS, $loginDataStr); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Content-Length: ' . strlen($loginDataStr) ]); // 开启Cookie自动存储和读取 curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile); curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile); // 忽略SSL证书验证(如果是自签证书可以开启,生产环境建议关闭) curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $loginRes = curl_exec($ch); $loginResult = json_decode($loginRes, true); // 2. 调用search_read接口,不需要手动传session相关头 $searchData = [ 'json-rpc' => '2.0', 'method' => 'call', 'params' => [ 'model' => 'res.users', 'fields' => ["id", "name", "login"], 'domain' => [], 'context' => new stdClass(), ], 'id' => 10, ]; $searchDataStr = json_encode($searchData); curl_setopt($ch, CURLOPT_URL, 'https://xxxxxxxxxxxxxxxxxxxxx/web/dataset/search_read'); curl_setopt($ch, CURLOPT_POSTFIELDS, $searchDataStr); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Content-Length: ' . strlen($searchDataStr) ]); $searchRes = curl_exec($ch); print_r($searchRes); // 用完删除临时Cookie文件 unlink($cookieFile); curl_close($ch);
方案2:JS调用适配
如果用fetch/axios调用,需要做以下配置:
- 开启withCredentials配置,允许跨域请求携带Cookie
- 确保Odoo服务配置了正确的CORS规则,允许你的前端域名访问,且允许携带凭证
- 先调用登录接口,后续请求浏览器会自动携带会话Cookie,不需要手动拼接
axios示例:
import axios from 'axios' const odooAxios = axios.create({ baseURL: 'https://你的Odoo域名', withCredentials: true, headers: { 'Content-Type': 'application/json' } }) // 先调用登录 await odooAxios.post('/web/session/authenticate', { 'json-rpc': '2.0', 'method': 'call', 'params': { 'db': 'xxxx', 'login': 'xxxx', 'password': 'xxxx', 'context': {} }, 'id': 10 }) // 再调用search_read,无需手动传session const res = await odooAxios.post('/web/dataset/search_read', { 'json-rpc': '2.0', 'method': 'call', 'params': { 'model': 'res.users', 'fields': ["id", "name", "login"], 'domain': [], 'context': {} }, 'id': 10 }) console.log(res.data)
方案3:使用XMLRPC接口(更稳定无需处理session)
Odoo官方提供的XMLRPC接口不需要处理会话,每次请求直接携带认证信息即可,适合后端服务调用场景,稳定性远高于web层的JSONRPC接口。
其他注意事项
- 确保Odoo配置文件中设置了
proxy_mode = True,适配反向代理HTTPS的场景,避免Cookie作用域错误 - 不要在生产环境关闭SSL证书验证,避免安全风险
- 如果是多数据库部署,确保所有请求的db参数一致
内容的提问来源于stack exchange,提问作者LyonOconner
相关产品推荐
相关产品推荐

