Discord.py Rewrite Giphy Cog报错:未关闭Connector解决方案咨询
解决discord.py中Giphy Cog的Unclosed client session错误
我之前也碰到过这个问题,你看到的Unclosed client session和Unclosed connector警告,本质是因为每次调用gif命令时都新建了一个aiohttp.ClientSession实例,虽然代码里写了await session.close(),但异步场景下很容易出现会话还没完全关闭就被回收的情况;如果命令执行中途抛出异常,session.close()甚至根本不会被执行,直接导致会话和连接泄漏,触发警告。
另外你的原代码还有几个小问题:
- 函数参数里的
json=None完全多余,而且原代码没导入json模块(修复前的版本) search.replace(' ', '+')不会修改原字符串(Python字符串是不可变类型),需要重新赋值- 没处理API请求失败的情况,比如返回404、500这类错误状态码
修复思路
正确的做法是给整个Cog创建一个全局的ClientSession,而不是每次命令调用都新建:
- 在Cog初始化时创建一次会话,所有命令共用这个会话
- 利用discord.py的
cog_unload钩子,在Cog被卸载(比如机器人重启、重载Cog)时关闭会话,确保资源被正确释放 - 移除命令内的会话创建/关闭逻辑,直接复用全局会话
修复后的完整代码(含额外优化)
import os import aiohttp import random import discord import json from discord.ext import commands from dotenv import load_dotenv load_dotenv() prefix = os.getenv("CLIENT_PREFIX") giphy_api = os.getenv("GIPHY_API_KEY") command_attrs = {'hidden': False} class FunCog(commands.Cog, name='Fun Commands', command_attrs=command_attrs): def __init__(self, client): self.client = client # 为Cog初始化全局会话,所有命令共用 self.session = aiohttp.ClientSession() def cog_unload(self): # Cog卸载时异步关闭会话,用create_task保证操作被事件循环执行 self.client.loop.create_task(self.session.close()) @commands.command(name='gif') async def _gif(self, ctx, *, search=""): embed = discord.Embed(colour=discord.Color.dark_gold()) try: if not search: # 用f-string拼接URL更清晰 response = await self.session.get(f'https://api.giphy.com/v1/gifs/random?api_key={giphy_api}') response.raise_for_status() # 捕获HTTP错误(比如401、500) data = await response.json() # 直接解析JSON,不用手动处理文本 embed.set_image(url=data['data']['images']['original']['url']) else: # 正确替换空格,重新赋值给search search = search.replace(' ', '+') response = await self.session.get( f'http://api.giphy.com/v1/gifs/search?q={search}&api_key={giphy_api}&limit=10') response.raise_for_status() data = await response.json() # 处理没有搜索结果的情况 if not data['data']: await ctx.send("没有找到匹配的GIF哦~") return # 根据实际返回的结果数量生成随机索引,避免越界 gif_choice = random.randint(0, len(data['data'])-1) embed.set_image(url=data['data'][gif_choice]['images']['original']['url']) await ctx.send(embed=embed) # 捕获HTTP请求相关错误 except aiohttp.ClientError as e: await ctx.send(f"请求GIF时出错了:{str(e)}") # 捕获JSON字段缺失的错误 except KeyError as e: await ctx.send(f"解析GIF数据时出错了:缺少字段 {str(e)}") def setup(client): client.add_cog(FunCog(client))
额外优化点说明
- 改用
f-string拼接URL,比字符串相加更简洁易维护 - 用
response.json()直接解析API返回的JSON,省去手动json.loads(await response.text())的步骤 - 添加
response.raise_for_status(),主动抛出HTTP请求错误,方便捕获和处理 - 替换固定的随机索引范围,用实际返回的结果数量计算索引,避免当搜索结果不足10个时出现索引越界错误
- 增加了异常处理逻辑,命令出错时能给用户友好的提示,而不是直接崩溃
内容的提问来源于stack exchange,提问作者user14267797
相关产品推荐
相关产品推荐

