Rust调用分页API循环拉取时balances长度返回0问题求助
问题描述
调用Algorand资产余额分页API时存在以下异常:
- 不传入分页参数、不启用循环逻辑单次请求时,
response.balances.len()返回值符合预期,可以正常统计当页余额条目数量 - 加入循环拉取全量分页逻辑后,循环内、循环外统计的余额长度返回值均为0
原有问题代码如下:
#[derive(Deserialize, Debug, Clone)] pub struct Algoholder { balances: Vec<Balance>, #[serde(rename = "current-round")] current_round: i64, #[serde(rename = "next-token")] next_token: Option<String>, } async fn get_algorand_data() -> i64 { let client = reqwest::Client::new(); let mut response; let mut current = "http://mainnet-idx.algonode.network/v2/assets/2751733/balances?currency-greater-than=0" .to_string(); loop { response = client .get(¤t) .header("x-api-key", &env::var("ALGOD_TOKEN").unwrap()) .header(CONTENT_TYPE, "application/json") .header(ACCEPT, "application/json") .header("pragma", "public") .send() .await .unwrap() .json::<Algoholder>() .await .unwrap(); if let Some(next) = &response.next_token { current = format!("{}&next={}", "http://mainnet-idx.algonode.network/v2/assets/2751733/balances?currency-greater-than=0", next); println!( "{}", format!("{}&next={}", &env::var("ALGOD_URL_1").unwrap(), next) ) } else { println!("Balances in loop : {}", &response.balances.len()); break; } } println!("Number of accounts {}", response.balances.len() as i64); response.balances.len() as i64 }
运行输出日志:
http://mainnet-idx.algonode.network/v2/assets/2751733/balances?currency-greater-than=0&next=UQIOTCZOKI3VIDIF7IY72DIZUCGLRSMHY65NCQHJ3IG6ZJPWTCG7PXMAUQ http://mainnet-idx.algonode.network/v2/assets/2751733/balances?currency-greater-than=0&next=777ILN5AAYHZ7RHSFZOAYVJHEJSRZRJCCXEAUMMHIY7AGR7ZMDTAU52BII Balances in loop : 0 Number of accounts 0
问题根因
- 没有累加所有分页的余额数据:每次循环都会把
response变量直接覆盖为当前页的返回结果,从未对各页的balances做聚合存储。当循环走到最后一页时,API返回的next-token为空,且最后一页本身不携带余额条目,因此最终读取到的balances.len()必然是0。 - 逻辑顺序错误:当前逻辑拿到下一页token后直接进入下一轮请求,完全没有处理当前页已经返回的余额数据。
修复方案
- 提前初始化一个可变数组,专门用来存储所有分页拉取到的余额条目
- 每请求成功一页,先把当前页的所有余额追加到总集合中,再判断是否存在下一页token
- 最终统计、返回总集合的长度,而非最后一页响应的余额长度
- 打印下一页请求地址时不要混用环境变量的地址和实际请求的硬编码地址,避免排查时日志和实际请求不一致
修复后的代码参考:
#[derive(Deserialize, Debug, Clone)] pub struct Algoholder { balances: Vec<Balance>, #[serde(rename = "current-round")] current_round: i64, #[serde(rename = "next-token")] next_token: Option<String>, } async fn get_algorand_data() -> i64 { let client = reqwest::Client::new(); // 初始化总余额集合 let mut all_balances = Vec::new(); let mut current = "http://mainnet-idx.algonode.network/v2/assets/2751733/balances?currency-greater-than=0" .to_string(); loop { let response = client .get(¤t) .header("x-api-key", &env::var("ALGOD_TOKEN").unwrap()) .header(CONTENT_TYPE, "application/json") .header(ACCEPT, "application/json") .header("pragma", "public") .send() .await .unwrap() .json::<Algoholder>() .await .unwrap(); // 先追加当前页的余额到总集合 all_balances.extend(response.balances); if let Some(next) = response.next_token { current = format!("{}&next={}", "http://mainnet-idx.algonode.network/v2/assets/2751733/balances?currency-greater-than=0", next); println!("Next page url: {}", current); } else { println!("Loop end, total balances count: {}", all_balances.len()); break; } } println!("Total number of accounts: {}", all_balances.len() as i64); all_balances.len() as i64 }
内容的提问来源于stack exchange,提问作者0xsegfault
相关产品推荐
相关产品推荐

