连接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
相关产品推荐
相关产品推荐

