python3.11+django5+channel4.2+websockets15,async_to_sync(channel_layer.gro...报错:TypeError: '<=' not supported between...
笔记本能正常运行代码,我把代码放到docker中运行时,就报错了,有大佬能提供一下排查思路吗?
[2025-05-16 16:01:52 +0800] [10] [ERROR] Exception in ASGI application
2025-05-16T08:01:52.104126449Z Traceback (most recent call last):
2025-05-16T08:01:52.104135607Z File "/usr/local/lib/python3.11/dist-packages/uvicorn/protocols/websockets/websockets_impl.py", line 243, in run_asgi
2025-05-16T08:01:52.104143020Z result = await self.app(self.scope, self.asgi_receive, self.asgi_send) # type: ignore[func-returns-value]
2025-05-16T08:01:52.104149921Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16T08:01:52.104156728Z File "/usr/local/lib/python3.11/dist-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__
2025-05-16T08:01:52.104171495Z return await self.app(scope, receive, send)
2025-05-16T08:01:52.104178527Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16T08:01:52.104185178Z File "/usr/local/lib/python3.11/dist-packages/channels/routing.py", line 48, in __call__
2025-05-16T08:01:52.104192070Z return await application(scope, receive, send)
2025-05-16T08:01:52.104198779Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16T08:01:52.104205490Z File "/usr/local/lib/python3.11/dist-packages/channels/sessions.py", line 44, in __call__
2025-05-16T08:01:52.104212313Z return await self.inner(dict(scope, cookies=cookies), receive, send)
2025-05-16T08:01:52.104219006Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16T08:01:52.104225747Z File "/usr/local/lib/python3.11/dist-packages/channels/sessions.py", line 261, in __call__
2025-05-16T08:01:52.104232508Z return await self.inner(wrapper.scope, receive, wrapper.send)
2025-05-16T08:01:52.104239246Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16T08:01:52.104245866Z File "/usr/local/lib/python3.11/dist-packages/channels/auth.py", line 185, in __call__
2025-05-16T08:01:52.104252606Z return await super().__call__(scope, receive, send)
2025-05-16T08:01:52.104259338Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16T08:01:52.104265941Z File "/usr/local/lib/python3.11/dist-packages/channels/middleware.py", line 24, in __call__
2025-05-16T08:01:52.104272697Z return await self.inner(scope, receive, send)
2025-05-16T08:01:52.104289053Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16T08:01:52.104295900Z File "/usr/local/lib/python3.11/dist-packages/channels/routing.py", line 118, in __call__
2025-05-16T08:01:52.104302776Z return await application(
2025-05-16T08:01:52.104339108Z ^^^^^^^^^^^^^^^^^^
2025-05-16T08:01:52.104346550Z File "/usr/local/lib/python3.11/dist-packages/channels/consumer.py", line 95, in app
2025-05-16T08:01:52.104353577Z return await consumer(scope, receive, send)
2025-05-16T08:01:52.104365288Z ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2025-05-16T08:01:52.104373394Z File "/usr/local/lib/python3.11/dist-packages/channels/consumer.py", line 58, in __call__
2025-05-16T08:01:52.104380267Z await await_many_dispatch(
2025-05-16T08:01:52.104386943Z File "/usr/local/lib/python3.11/dist-packages/channels/utils.py", line 57, in await_many_dispatch
2025-05-16T08:01:52.104393808Z await task
2025-05-16T08:01:52.104400696Z TypeError: '<=' not supported between instances of 'str' and 'int'
以下是我的部分代码:
async_to_sync(channel_layer.group_send)(
md5_group,
{"type": "send.message",
"message": {"code": 200, "type": "job_msg", "data": '\x1B[32m开始执行Shell脚本...\x1B[0m\r\n\r\n'}}
)
class SSHConsumer(WebsocketConsumer):
def __init__(self, *args, **kwargs):
super().__init__(args, kwargs)
self.group_name = None
self.ssh = None
def auth(self, token, username):
try:
# ================单用户登录逻辑=====================
single_login = SingleLogin(username)
if single_login.get_black_list(token):
logger.warning(f"用户 {username} 被强制下线 (Token: {token})")
self.send_to_ws_mes(401, "auth_error", '已有用户登录,当前强制下线')
return False
# ================单用户登录逻辑=====================
if token == "undefined":
logger.error(f"Token无效")
self.send_to_ws_mes(401, "auth_error", f"Token无效")
return False
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
jwt_decode_handler(token)
except ExpiredSignatureError as e:
logger.error(f"Token过期,{e}")
self.send_to_ws_mes(401, "auth_error", f"Token过期,{e}")
return False
except InvalidTokenError as e:
logger.error(f"Token验证失败,{e}")
self.send_to_ws_mes(401, "auth_error", f"Token验证失败,{e}")
return False
except PyJWTError as e:
logger.error(f"Token验证异常,{e}")
self.send_to_ws_mes(401, "auth_error", f"Token验证异常,{e}")
return False
return True
def send_message(self, event):
"""接收 Channel Layer 消息并发送给 WebSocket 客户端"""
message = event["message"]
try:
self.send(text_data=json.dumps(message))
except Exception as e:
logger.error(e)
def send_to_ws_mes(self, code, msg_type, data):
try:
message = {
"code": code, # 状态码
"type": msg_type, # 消息类型
"data": data # 实际数据
}
self.send(json.dumps(message))
except AttributeError as e:
logger.error(f"WebSocket未正确初始化,无法发送消息: {e}")
except TypeError as e:
logger.error(f"消息序列化失败 (类型错误): {e}\n原始数据: {data}")
except Exception as e:
logger.error(f"发送消息时发生未知错误: {e}\n{traceback.format_exc()}")
def connect(self):
try:
self.accept()
token = self.scope["cookies"]["token"]
print(token)
if not self.auth(token, self.scope["cookies"]["username"]):
self.close()
return
self.group_name = self.scope['url_route']['kwargs']['group_name']
# 将当前频道加入频道组
async_to_sync(self.channel_layer.group_add)(
self.group_name,
self.channel_name
)
# 加入组后设置活动时间,方便在ssh_client.py中获取self.group_name组是否断开ws连接
cache.set(f'group_activity:{self.group_name}', time.time(), timeout=1800)
if self.group_name == "terminal":
host_info = self.scope["query_string"].decode()
host_id = int(host_info.split('&')[0].split('=')[1])
host_obj = HostList.objects.get(id=host_id)
host_ip = host_obj.connect_ip
host_port = host_obj.port
user_name = host_obj.user
user_pass = Password().decrypt(host_obj.password)
self.ssh = StreamConsumer(websocket=self)
self.ssh.connect(host_ip, host_port, user_name, user_pass)
except Exception as e:
logger.error(f"WebSocket连接初始化失败: {e}\n{traceback.format_exc()}") # 替换print为详细日志
self.close()
# print(f"WS连接报错:{e}")
def close_connection(self, event=''):
"""收到关闭指令时,关闭 WebSocket 连接"""
self.close() # 关闭连接
def disconnect(self, close_code):
try:
async_to_sync(self.channel_layer.group_discard)(
self.group_name,
self.channel_name
)
if self.ssh:
self.ssh.close()
# 删除组活动时间记录,如果 self.group_name 组断开了连接,就删除缓存 group_activity:{self.group_name} 键
cache.delete(f'group_activity:{self.group_name}')
logger.warning(f'已删除 group_activity:{self.group_name} ws组')
except TypeError as e:
logger.error(f"断开连接时发生错误: {e}\n{traceback.format_exc()}")
# logger.error(f"已断开websocket连接:{e}")
def receive(self, text_data=None, bytes_data=None):
try:
text_data = json.loads(text_data)
if text_data.get('flag') == 'resize':
# 转换cols和rows为整数
cols = int(text_data['cols'])
rows = int(text_data['rows'])
if self.ssh:
self.ssh.resize_pty(cols=cols, rows=rows)
elif text_data.get('type') == 'heartbeat':
message = {
"code": 200,
"type": "heartbeat",
"data": "pong",
}
self.send(json.dumps(message))
else:
data = text_data.get('entered_key', '')
self.ssh.shell(data=data)
except json.JSONDecodeError as e:
logger.error(f"接收到的消息格式错误: {text_data}\n错误详情: {e}")
except KeyError as e:
logger.error(f"消息缺少必要字段: {e}\n原始数据: {text_data}")
except Exception as e:
logger.error(f"处理消息时发生未知错误: {e}\n{traceback.format_exc()}")