Rust 异步 HTTP 实战:用 reqwest 与 tokio 并发抓取多个接口

test12026-09-305 次阅读

为什么用 reqwest

Rust 里做 HTTP 客户端,reqwest 是事实标准:它基于 tokio 异步运行时,API 简洁,支持 JSON、超时、拦截器。配合 futures 的 join_all,可以轻松把多个独立请求并发发出去,而不是串行等待。

依赖声明

在 Cargo.toml 里启用 tokio 的完整特性,并给 reqwest 打开 json 特性。

[dependencies]
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.12", features = ["json"] }
futures = "0.3"

发起单个请求

最简单的用法是 reqwest::get 后链式 await,再用 .json 把响应反序列化成 serde 支持的类型。

use reqwest::Error;

#[tokio::main]
async fn main() -> Result<(), Error> {
    let resp = reqwest::get("https://api.example.com/health")
        .await?
        .json::<serde_json::Value>()
        .await?;
    println!("status: {:?}", resp);
    Ok(())
}

并发抓取多个 URL

把抓取逻辑抽成返回 Result 的异步函数,再用 future::join_all 一次性等所有任务完成。每个请求单独设超时,避免某个慢接口拖垮整体。

use futures::future;
use std::time::Duration;

async fn fetch(url: &str) -> Result<String, reqwest::Error> {
    let body = reqwest::Client::new()
        .get(url)
        .timeout(Duration::from_secs(5))
        .send()
        .await?
        .text()
        .await?;
    Ok(body)
}

#[tokio::main]
async fn main() {
    let urls = vec![
        "https://api.example.com/a",
        "https://api.example.com/b",
        "https://api.example.com/c",
    ];
    let results = future::join_all(urls.iter().map(|u| fetch(u))).await;
    for (url, res) in urls.iter().zip(results) {
        match res {
            Ok(body) => println!("{} -> {} bytes", url, body.len()),
            Err(e) => eprintln!("{} -> error: {}", url, e),
        }
    }
}

错误处理与超时要点

  • reqwest 的错误实现了 std::error::Error,可以直接用 ? 向上传播,或用 anyhow 收口。
  • 每个 Client 请求都设 timeout,否则默认无限等待,一个卡住的远端会让任务长期挂起。
  • 复用同一个 reqwest::Client 而不是每次新建,能共享连接池,显著降低握手开销。
  • join_all 会并发驱动所有 future,数量很大时要考虑限流,避免瞬间打满文件描述符或对端连接数。
T

test1

文章作者

为什么用 reqwest Rust 里做 HTTP 客户端,reqwest 是事实标准:它基于 tokio 异步运行时...

分类
技术
发布时间
2026-09-30
字数
约 1733 字
阅读
5 次