Python使用kombu连接信息中包含#号问题排查方式
本文记录Python项目在生产环境中使用kombu连接RabbitMQ时,因连接字符串包含#号导致端口解析失败的排查过程。通过分析源码发现urlsplit对特殊字符处理差异,指出#号被误认为片段标识符导致端口错位。建议对URL中的特殊字符进行编码处理以解决该问题。
在将Python项目部署至生产环境时,遭遇了一个异常错误。
系统抛出ValueError异常,提示端口无法转换为整数值,具体报错内容为:Port could not be cast to integer value as 'guest'。
该问题在测试环境及本地调试阶段均未出现,仅在部署至生产环境后显现。本章将复现由MQ连接配置引发的错误信息,并详细记录问题的排查过程。
版本信息
| 框架 | 版本 |
|---|---|
| python | 3.11.7 |
| kombu | 5.3.4 |
环境搭建
python 虚拟环境
Python 虚拟环境(Virtual Environment)旨在提供一个隔离的 Python 解释器运行空间,允许为各个 Python 项目独立安装依赖包,从而避免干扰全局 Python 环境或其他项目。
通过这种方式,可确保每个项目拥有独立且一致的依赖环境,有效规避版本冲突及依赖混乱的问题。
Python 生态中存在多个用于创建和管理虚拟环境的流行工具,其中最为常用的是 venv 和 virtualenv。
venv 创建 python 虚拟环境
python -m venv .venv
执行该命令后,系统将创建一个虚拟环境并生成 .venv 文件夹,目录结构如下所示。

激活虚拟环境
.venv\Scripts\activate

激活虚拟环境后,命令行提示符前会显示括号及虚拟环境名称。

退出虚拟环境
deactivate

虚拟环境下查看python、pip版本

查询pip 配置信息
(.venv) F:\Python\mq>pip config list global.index-url='http://mirrors.aliyun.com/pypi/simple/' install.trusted-host='mirrors.aliyun.com'
安装依赖
编写 requirements.txt
kombu==5.3.4
在虚拟环境里面安装依赖
pip install -r requirements.txt
问题复现以及问题排查
1.消息发布端 hello_publisher.py
from __future__ import annotations
import datetime
from kombu import Connection
with Connection('amqp://guest:guest#2024@localhost:5672//') as conn:
simple_queue = conn.SimpleQueue('simple_queue')
message = f'helloworld, sent at {datetime.datetime.today()}'
simple_queue.put(message)
print(f'Sent: {message}')
simple_queue.close()2.在虚拟环境运行代码
运行后出现如下报错信息。
(.venv) F:\Python\mq>python hello_publisher.py Traceback (most recent call last): File "F:\Python\mq\hello_publisher.py", line 7, in <module> with Connection('amqp://guest:guest#2024@localhost:5672//') as conn: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "F:\Python\mq\.venv\Lib\site-packages\kombu\connection.py", line 203, in __init__ url_params = parse_url(hostname) ^^^^^^^^^^^^^^^^^^^ File "F:\Python\mq\.venv\Lib\site-packages\kombu\utils\url.py", line 38, in parse_url scheme, host, port, user, password, path, query = _parse_url(url) ^^^^^^^^^^^ File "F:\Python\mq\.venv\Lib\site-packages\kombu\utils\url.py", line 70, in url_to_parts parts.port, ^^^^^^ File "E:\Anaconda\Lib\urllib\parse.py", line 182, in port raise ValueError(f"Port could not be cast to integer value as {port!r}") ValueError: Port could not be cast to integer value as 'guest'
根据报错堆栈信息,首先定位到代码执行的具体行。
File "F:\Python\mq\.venv\Lib\site-packages\kombu\utils\url.py", line 70
在此处设置断点进行调试(若生产服务无法调试,可通过print语句输出相关信息)。
3.调试出问题的代码
报错的代码方法如下。
def url_to_parts(url):
# type: (str) -> urlparts
"""Parse URL into :class:`urlparts` tuple of components."""
scheme = urlparse(url).scheme
schemeless = url[len(scheme) + 3:]
# parse with HTTP URL semantics
parts = urlparse('http://' + schemeless)
path = parts.path or ''
path = path[1:] if path and path[0] == '/' else path
return urlparts(
scheme,
unquote(parts.hostname or '') or None,
parts.port,
unquote(parts.username or '') or None,
unquote(parts.password or '') or None,
unquote(path or '') or None,
dict(parse_qsl(parts.query)),
)parts.port 获取的值源自 urlparse 方法解析的结果。

执行完 urlparse 方法后,获取到的数值如下。

port 的解析在 urlparse 这一步出现异常,重点分析该方法的逻辑。

经过调试,发现问题出在切割方法里面 urllib.parse.urlsplit,具体处理出现问题的代码片段如下。

链接中包含 # 号,导致切割后端口号错位,未能正确获取到端口值。
去除链接中的 # 号后,解析数据恢复正常。

链接中不包含 # 号时,端口可以正常解析。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









