python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python kombu连接信息中包含#号问题排查

Python使用kombu连接信息中包含#号问题排查方式

作者:Chengdu.S

文章描述了在部署Python项目到生产环境时遇到的一个错误,即端口号无法正确转换为整数值,该错误在测试环境和本地调试中没有出现,但在生产环境中才出现,通过分析错误信息和代码,作者发现问题出在URL解析过程中,特别是在处理包含特殊字符(如#号)的URL时

python 项目部署生产环境遇到一个错误问题:

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

测试环境和本地调试都没有问题,但是到生产之后就有问题,本章复现有问题的mq连接配置的导致的错误信息,记录问题排查过程

版本信息

框架版本
python3.11.7
kombu5.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,具体处理出问题代码在如下片段

链接中有 # 号导致切割之后端口号错位未获取到

去除链接中的#号的正常解析的数据如下

链接中没有 # 号之后,端口可以正常解析了

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文