You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何通过Discord API绕过100条消息限制获取频道全部消息并优化现有代码?

如何通过Discord API绕过100条消息限制获取频道全部消息并优化现有代码?

嘿,你已经搞定了大部分核心逻辑啦!Discord API单次请求最多返回100条消息的限制确实得靠分页来突破,你的before参数思路完全正确。不过现有代码还有几个可以优化的地方,比如异步逻辑的顺序问题、全局变量的副作用,还有速率限制的处理,我来帮你调整得更可靠、更简洁:

先聊聊现有代码的小问题

  • slice.map(async ...)的方式会导致异步操作乱序,因为map不会等待每个async函数执行完,可能出现消息收集顺序不对的情况
  • 全局变量contents容易引发意外副作用,最好把它封装在函数内部
  • 固定3000ms的延迟不是最优解,Discord API的速率限制可以通过更智能的方式处理(比如自动识别重试时间)
  • TypeScript类型定义不够明确,比如content类型没声明,函数返回值类型可以更精准

优化后的完整代码

import axios from "axios";

// 定义Discord消息的基础类型,给TypeScript提供类型提示
interface DiscordMessage {
  id: string;
  content: string;
  // 你需要的其他字段(比如作者、时间戳)可以在这里补充
}

const api = axios.create({
  baseURL: "https://discord.com/api/v9/",
  headers: {
    Authorization: "xxxx-xxxx--xxxx" // 替换成你的有效令牌
  }
});

// 自动处理Discord速率限制:拦截429错误,按返回的重试时间自动重试
api.interceptors.response.use(
  response => response,
  async error => {
    if (error.response?.status === 429) {
      const retryAfter = error.response.data.retry_after || 3000;
      console.log(`触发速率限制,${retryAfter}ms后重试`);
      await new Promise(resolve => setTimeout(resolve, retryAfter));
      return api.request(error.config);
    }
    throw new Error(`[ERROR] - 请求失败: ${error.message}`);
  }
);

// 封装单页消息获取函数,返回明确的类型
async function getChannelMessages(
  channelId: string,
  queryParams: { before?: string; limit?: number } = { limit: 100 }
): Promise<DiscordMessage[]> {
  try {
    const params = new URLSearchParams();
    if (queryParams.before) params.append("before", queryParams.before);
    params.append("limit", queryParams.limit.toString());
    
    const response = await api.get(`/channels/${channelId}/messages`, { params });
    return response.data;
  } catch (error) {
    throw new Error(`[ERROR] - 获取消息失败: ${(error as Error).message}`);
  }
}

// 递归+循环获取所有消息,内部维护消息列表,避免全局变量
async function getAllChannelMessages(channelId: string): Promise<string[]> {
  const allMessages: string[] = [];
  let lastMessageId: string | undefined;

  while (true) {
    const messages = await getChannelMessages(channelId, { before: lastMessageId });
    if (messages.length === 0) break; // 没有更多消息,退出循环

    // 收集当前页的消息内容
    const messageContents = messages.map(msg => msg.content);
    allMessages.push(...messageContents);

    // 更新lastMessageId,用于下一页请求
    lastMessageId = messages[messages.length - 1].id;

    // 可选:如果担心触发速率限制,这里可以加个小延迟(不过拦截器已经处理了429)
    // await new Promise(resolve => setTimeout(resolve, 1000));
  }

  return allMessages;
}

// 使用示例
getAllChannelMessages("111654654546541585")
  .then(contents => {
    console.log("所有消息内容:", contents);
    // 这里可以添加你的后续处理逻辑
  })
  .catch(error => {
    console.error(error.message);
  });

优化点说明

  1. 类型安全:添加DiscordMessage接口,让TypeScript提供准确的类型提示,避免类型错误
  2. 异步逻辑更可靠:用while循环代替递归+map,确保消息按时间顺序收集,不会出现异步乱序
  3. 智能速率限制处理:通过axios拦截器自动识别429错误,根据Discord返回的retry_after时间重试,比固定延迟更灵活
  4. 无全局变量:消息列表封装在函数内部,避免全局副作用,代码更健壮
  5. 清晰的函数拆分:把单页消息获取和全部消息获取逻辑分开,可读性和可维护性更高

这样调整后,你的代码不仅能稳定获取所有频道消息,还更易扩展和维护~

备注:内容来源于stack exchange,提问作者syber man

火山引擎 最新活动