You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

连接Odoo 15时偶发EOF协议违规错误的排查求助

Django 连接 Odoo 偶发 SSL EOF 协议错误问题

问题场景

我用Django开发了一个连接Odoo实例的应用,核心视图代码如下:

userlog = request.user
if request.method == 'GET':
    # return render(request, 'inventory_updates.html')
    products = models.execute_kw(db, uid, password, 'product.product', 'search_read', [[['type', 'in', ['product', 'consu']]]], 
    {'fields': ['name']})
    return render(request, 'inventory_updates.html', {'products': products})

向该视图发起GET请求时,偶尔会触发以下SSL错误:

EOF occurred in violation of protocol (_ssl.c:2396)

我的Odoo连接代码:

models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url),allow_none=True,verbose=False, use_datetime=True,context=ssl._create_unverified_context())

common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url),allow_none=True,verbose=False, use_datetime=True,context=ssl._create_unverified_context())

服务器环境:Ubuntu 20.04,搭载Nginx,Django和Odoo部署在同一服务器。我怀疑问题和自签名SSL有关,但无法理解为什么错误是偶发而非持续出现。已经检查过Python TLS版本和Nginx的TLS配置,现在需要可行的解决办法。

解决办法

1. 显式指定SSL/TLS版本

偶发EOF错误可能是Python的xmlrpc.client默认TLS版本协商存在兼容性问题,搭配自签名证书时更容易出现。可以强制指定兼容的TLS版本(比如TLSv1.2):

import ssl
from xmlrpc.client import ServerProxy

# 创建指定TLS版本的SSL上下文
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
# 强制锁定TLSv1.2版本
ssl_context.min_version = ssl.TLSVersion.TLSv1_2
ssl_context.max_version = ssl.TLSVersion.TLSv1_2

models = ServerProxy('{}/xmlrpc/2/object'.format(url),
                     allow_none=True,
                     verbose=False,
                     use_datetime=True,
                     context=ssl_context)

common = ServerProxy('{}/xmlrpc/2/common'.format(url),
                     allow_none=True,
                     verbose=False,
                     use_datetime=True,
                     context=ssl_context)

2. 给Odoo请求添加重试机制

偶发错误可能是网络或Nginx连接池的临时波动导致,给请求加上重试逻辑:

import xmlrpc.client
import time

def safe_odoo_call(models, *args, **kwargs):
    max_retries = 3
    retry_delay = 1
    for attempt in range(max_retries):
        try:
            return models.execute_kw(*args, **kwargs)
        except (xmlrpc.client.Fault, ConnectionError, ssl.SSLError) as e:
            if attempt == max_retries - 1:
                raise e
            time.sleep(retry_delay)
            retry_delay *= 2

# 视图中替换原调用逻辑
products = safe_odoo_call(models, db, uid, password, 'product.product', 'search_read', [[['type', 'in', ['product', 'consu']]]], {'fields': ['name']})

3. 优化Nginx的SSL配置

针对自签名证书和同服务器部署的场景,调整Nginx配置减少连接异常:
在Nginx对应server块中添加/修改以下配置:

# 指定兼容的TLS版本
ssl_protocols TLSv1.2 TLSv1.3;
# 使用安全加密套件
ssl_ciphers HIGH:!aNULL:!MD5;
# 启用SSL会话缓存,减少重复握手
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 开启长连接,优化同服务器请求的稳定性
keepalive_timeout 65;
keepalive_requests 100;

4. 替换xmlrpc.client为更灵活的请求方案

xmlrpc.client的SSL处理较老旧,改用requests配合自定义传输类,更灵活控制SSL逻辑:

import xmlrpc.client
import requests
from requests.adapters import HTTPAdapter
from urllib3.poolmanager import PoolManager
import ssl

class TLSAdapter(HTTPAdapter):
    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(
            num_pools=connections,
            maxsize=maxsize,
            block=block,
            ssl_version=ssl.PROTOCOL_TLSv1_2,
            cert_reqs=ssl.CERT_NONE
        )

session = requests.Session()
session.mount('https://', TLSAdapter())

class RequestsTransport(xmlrpc.client.Transport):
    def send_request(self, host, handler, request_body, verbose):
        url = f"https://{host}{handler}"
        response = session.post(url, data=request_body, headers={'Content-Type': 'text/xml'})
        return response.status_code, response.headers, response.content

# 使用自定义传输创建ServerProxy
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url),
                                   allow_none=True,
                                   verbose=False,
                                   use_datetime=True,
                                   transport=RequestsTransport())

内容的提问来源于stack exchange,提问作者apexprogramming

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 23:05:18