Ruby循环调用分页API时哈希更新及offset参数失效问题
Ruby分页拉取接口数据构建哈希映射问题修复
已更新采用getEntitlementList()方法实现相关逻辑。本人是Ruby初学者,尝试分步拉取数据并更新哈希结构,此前关于Ruby拆分与循环的问题已解决。
遇到的核心问题
- 分页参数失效:按步长250依次设置offset参数(取值依次为0、250、500直至3000),但接口每次返回的响应完全相同,未返回不同分页的数据。
- 哈希结果不全:目标接口共有3000条数据,单次调用最多拉取250条,预期每次拉取到新分页数据时更新同一个哈希对象,最终得到包含所有条目的哈希,但实际最终哈希仅保留最后一次拉取的250条数据。此前已尝试使用
entitlementHash.update、entitlementHash.store、entitlementHash.merge方法实现,均未达到预期效果。
接口规则说明
limit:整数类型,指定单次API调用返回的最大记录数,未指定时使用默认值,单页最大支持返回250条记录。offset:整数类型,指定从集合起始位置开始的第一条结果的偏移量,offset基于记录数而非页数计算,索引从0开始。例如offset=0、limit=20将返回0-19号记录,offset=1、limit=20将返回1-20号记录,取值范围为0到最后一条记录的索引之间。
最终需要构建
displayableName(大写格式)与id一一对应的完整哈希映射表。
现有代码
接口请求方法
def getEntitlementList(url,header,source,limit,offset) # 该方法用于拉取指定数据源的现有权限列表 # 该列表用于构建displayableName与Id映射的哈希表 # 返回哈希映射结构 uri = URI.parse( "#{url}/cc/api/entitlement/list?limit=#{limit}&offset=#{offset}&CISApplicationId=#{source}" ) puts uri http = Net::HTTP.new( uri.host, uri.port ) http.use_ssl = true request = Net::HTTP::Get.new( uri.request_uri, header ) response = http.request( request ) case response when Net::HTTPSuccess responseBody = JSON.parse(response.body) when Net::HTTPUnauthorized puts "#{source} Entitlements Hash Map creation is a Failure!" puts "Error: Unauthorized." when Net::HTTPServerError puts "#{source} Entitlements Hash Map creation is a Failure!" puts "Error: Server Error." else puts "#{source} Entitlements Hash Map creation is a Failure!" puts "Error: #{response.code}" end return responseBody end
分页拉取逻辑
limit = 250 entitlementHash = Hash.new (0..3000).step(250) do |offset| responseBody = getEntitlementList(url,header,source,limit,offset) count = responseBody['count'] entitlementList = responseBody['items'] entitlementList.each {|a| entitlementHash["#{a['displayableName'].upcase()}"] = a['id']} puts "updated entitlementHash size: #{entitlementHash.size}" end return entitlementHash
问题根因与修复方案
1. 分页始终返回第一页数据
核心问题是构造请求URI时,参数分隔符错误使用了HTML转义字符&,Ruby的URI解析不会自动将该转义符转换为普通的&,导致服务端无法正确识别offset和CISApplicationId参数,始终使用默认offset=0返回第一页数据。
修复方式:将URI拼接逻辑中的所有&替换为普通&即可。
2. 哈希仅保留250条数据
这个问题是分页失效的连锁反应:每次请求拿到的都是第一页的250条重复数据,无论用哪种哈希写入方法,都是对相同的250个key重复赋值,最终哈希大小自然停留在250。修复分页参数问题后,现有逐行写入哈希的逻辑本身完全可用,不需要额外替换merge/update类方法。
额外优化
现有逻辑写死循环到offset=3000,灵活性差,建议根据接口返回的总记录数count动态判断循环终止条件,同时增加重名校验,避免不同条目displayableName大写后重复导致ID被覆盖。
修复后完整参考代码
def getEntitlementList(url,header,source,limit,offset) # 替换&为普通&,修复参数解析问题 uri = URI.parse( "#{url}/cc/api/entitlement/list?limit=#{limit}&offset=#{offset}&CISApplicationId=#{source}" ) puts uri http = Net::HTTP.new( uri.host, uri.port ) http.use_ssl = true request = Net::HTTP::Get.new( uri.request_uri, header ) response = http.request( request ) responseBody = nil case response when Net::HTTPSuccess responseBody = JSON.parse(response.body) when Net::HTTPUnauthorized puts "#{source} Entitlements Hash Map creation is a Failure!" puts "Error: Unauthorized." when Net::HTTPServerError puts "#{source} Entitlements Hash Map creation is a Failure!" puts "Error: Server Error." else puts "#{source} Entitlements Hash Map creation is a Failure!" puts "Error: #{response.code}" end return responseBody end # 分页拉取逻辑 limit = 250 entitlementHash = {} offset = 0 loop do responseBody = getEntitlementList(url, header, source, limit, offset) break unless responseBody.is_a?(Hash) && responseBody['items'].is_a?(Array) total_count = responseBody['count'].to_i entitlementList = responseBody['items'] entitlementList.each do |item| name_key = item['displayableName'].to_s.upcase # 重名告警,避免数据覆盖 if entitlementHash.key?(name_key) puts "警告:重名权限#{name_key},原ID:#{entitlementHash[name_key]},新ID:#{item['id']}" end entitlementHash[name_key] = item['id'] end puts "已拉取offset=#{offset}页数据,当前哈希总条目数:#{entitlementHash.size}" offset += limit # 拉取完全部数据后终止循环 break if offset >= total_count end return entitlementHash
内容的提问来源于stack exchange,提问作者born2Learn
相关产品推荐
相关产品推荐

