You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 07:45:54