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

Ruby调用Discord API移除打印语句后JSON解析报类型错误

问题背景

分页调用Discord API拉取服务器成员数据,接口单次最多可返回1000条用户记录,需循环请求直到获取全部用户。
代码中保留p ["BEFORE PARSE", response.body]打印response.body的语句时,程序可正常运行,顺利完成全部17轮分页请求;若移除该打印语句,在对用户对象调用dig方法时会抛出json no implicit conversion of String into Integer (TypeError)错误:第10轮迭代的返回结果中出现了['global', false]结构,而非预期的用户实例对象。

相关实现代码如下:

def initialize
  @role_mapping = {}
  @students = {}
  @connection = Faraday.new(
    url: 'https://discord.com/api/v10',
    params: {},
    headers: {
      'Content-Type' => 'application/json',
      'Authorization' => 'Bot 1234abcd'
    }
  )
end

...

def request_members(guild_id, after = "0", limit = 1000)
  response = connection.get("guilds/#{guild_id}/members") do |req|
    req.params['limit'] = limit
    req.params['after'] = after
  end

  p ["BEFORE PARSE", response.body]
    
  parsed_response = JSON.parse(response.body)

  updated_after = nil
  updated_after = parsed_response[-1]['user']['id'] if parsed_response[-1]

  parsed_response.each do |user|
    user_id = user.dig('user', 'id')

    roles = user['roles'].filter_map do |role_id|
      @role_mapping[role_id] if @role_mapping[role_id]
    end

    if @students[user_id]
      @students[user_id] = @students[user_id] + roles
    else
      @students[user_id] = roles
    end
  end

  request_members(guild_id, updated_after) if updated_after
end
根本原因
  1. 核心问题是代码未做API响应状态校验,移除打印语句后请求无间隔触发了Discord的速率限制。
  2. 保留打印语句时,p执行控制台输出是同步IO操作,会在每轮请求之间自然增加几十到上百毫秒的延迟,请求频率没有触发Discord API的限流阈值,接口正常返回成员列表数组,后续解析逻辑可以正常运行。
  3. 移除打印语句后,递归请求没有任何等待间隔,请求速度过快,第10轮请求触发了Discord的429速率限制,此时接口返回的不是成员列表数组,而是限流响应的JSON对象,结构如下:
    {
      "global": false,
      "message": "You are being rate limited.",
      "retry_after": 0.214
    }
    
  4. 此时JSON.parse(response.body)得到的是Ruby Hash对象,而非预期的数组。代码没有做类型校验直接遍历:
    • 对Hash调用parsed_response[-1]时,因为Hash不存在整数键-1,返回nil,所以取最后一个用户ID的逻辑不会执行
    • 对Hash调用each遍历,Ruby会逐组返回键值对构成的数组,第一个遍历到的元素就是['global', false],也就是观察到的异常结构
    • 后续对这个长度为2的数组调用dig('user', 'id')时,数组索引只接受整数类型,传入字符串'user'就会抛出no implicit conversion of String into Integer的类型错误。
修复方向
  • 给Faraday配置状态码校验中间件,遇到4xx、5xx响应时做对应处理,不要直接把错误响应当成正常业务数据解析
  • 不要用无间隔递归的方式发请求,严格遵循Discord API的限流规则:如果收到429响应,按返回的retry_after字段等待对应时间再重试,也可以主动在每轮请求之间增加合理延迟
  • 解析响应前先校验数据结构,确认返回的是成员数组后再走后续遍历逻辑,避免异常结构进入业务代码。

内容的提问来源于stack exchange,提问作者Sean Magyar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 21:36:25