Rust网络请求库rquest的使用:高效异步HTTP客户端与Rust插件库集成

Rust网络请求库rquest的使用:高效异步HTTP客户端与Rust插件库集成

特性

  • 支持多种请求体格式:普通文本、JSON、urlencoded、multipart
  • 内置Cookie存储
  • 自定义Header顺序
  • 重定向策略
  • 代理轮换
  • 证书存储
  • WebSocket升级
  • 基于BoringSSL的HTTPS
  • HTTP/2 TLS模拟

示例代码

首先需要在Cargo.toml中添加依赖:

[dependencies]
tokio = { version = "1", features = ["full"] }
rquest = "5"
rquest-util = "2"

以下是完整的异步示例代码:

use rquest::Client;
use rquest_util::Emulation;

#[tokio::main]
async fn main() -> Result<(), rquest::Error> {
    // 构建客户端并设置Firefox136浏览器模拟
    let client = Client::builder()
        .emulation(Emulation::Firefox136)
        .build()?;

    // 发送GET请求并获取响应
    let resp = client.get("https://tls.peet.ws/api/all").send().await?;
    
    // 打印响应文本
    println!("{}", resp.text().await?);

    Ok(())
}

完整示例demo

下面是一个更完整的示例,展示了如何使用rquest发送POST请求并处理JSON响应:

use rquest::Client;
use rquest_util::Emulation;
use serde_json::Value;
use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), rquest::Error> {
    // 1. 构建客户端并设置Chrome浏览器模拟
    let client = Client::builder()
        .emulation(Emulation::Chrome120)
        .build()?;

    // 2. 准备POST请求数据
    let mut data = HashMap::new();
    data.insert("username", "testuser");
    data.insert("password", "testpass");

    // 3. 发送POST请求
    let resp = client
        .post("https://example.com/api/login")
        .json(&data)
        .send()
        .await?;

    // 4. 处理JSON响应
    if resp.status().is_success() {
        let json: Value = resp.json().await?;
        println!("登录成功: {:?}", json);
    } else {
        println!("请求失败,状态码: {}", resp.status());
    }

    Ok(())
}

模拟功能说明

HTTP/2 over TLS

  • JA3/JA4/Akamai指纹由于TLS加密的复杂性和HTTP/2的普及,无法准确模拟浏览器指纹
  • rquest不支持解析这些指纹字符串进行模拟,用户应根据自身需求自定义配置

设备模拟

  • 大多数浏览器设备模型共享相同的TLS和HTTP/2配置,仅User-Agent不同
  • 浏览器设备模拟模板由rquest-util管理

构建注意事项

避免与依赖openssl-sys的包一起编译,因为它与boring-sys共享相同的前缀符号,可能导致链接失败。即使编译成功,同时使用openssl-sysboring-sys也可能导致内存段错误。

安装BoringSSL的构建依赖:

sudo apt-get install build-essential cmake perl pkg-config libclang-dev musl-tools -y

cargo build --release

许可证

Apache-2.0许可证


1 回复

以下是根据您提供的内容整理的完整示例代码,首先展示内容中的示例,然后提供完整的demo实现:

内容中提供的示例汇总

  1. 基本GET请求示例:
use rquest::Client;

#[tokio::main]
async fn main() -> Result<(), rquest::Error> {
    let client = Client::new();
    let response = client.get("https://httpbin.org/get")
        .send()
        .await?;
    
    println!("Status: {}", response.status());
    println!("Body: {}", response.text().await?);
    
    Ok(())
}
  1. POST请求示例:
use rquest::Client;
use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), rquest::Error> {
    let client = Client::new();
    let mut data = HashMap::new();
    data.insert("key", "value");
    
    let response = client.post("https://httpbin.org/post")
        .json(&data)
        .send()
        .await?;
    
    println!("Response: {}", response.text().await?);
    
    Ok(())
}
  1. 插件系统示例:
use rquest::{Client, Plugin, Request, Response};
use std::time::Instant;

struct TimingPlugin;

#[async_trait::async_trait]
impl Plugin for TimingPlugin {
    async fn on_request(&self, request: &mut Request) {
        request.extensions_mut().insert(Instant::now());
    }

    async fn on_response(&self, response: &mut Response) {
        if let Some(start) = response.extensions().get::<Instant>() {
            let duration = start.elapsed();
            println!("Request took {}ms", duration.as_millis());
        }
    }
}

完整示例Demo

//! 完整的rquest使用示例,包含GET/POST请求、插件系统和错误处理

use rquest::{Client, Plugin, Request, Response, Error};
use std::collections::HashMap;
use std::time::{Instant, Duration};
use async_trait::async_trait;
use futures::future::join_all;

/// 自定义插件:记录请求耗时和状态
struct MetricsPlugin;

#[async_trait]
impl Plugin for MetricsPlugin {
    async fn on_request(&self, request: &mut Request) {
        request.extensions_mut().insert(Instant::now());
    }

    async fn on_response(&self, response: &mut Response) {
        if let Some(start) = response.extensions().get::<Instant>() {
            let duration = start.elapsed();
            println!(
                "Request to {} took {}ms, status: {}",
                response.url(),
                duration.as_millis(),
                response.status()
            );
        }
    }
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    // 1. 创建配置化的客户端
    let client = Client::builder()
        .timeout(Duration::from_secs(5))
        .plugin(MetricsPlugin)
        .build();

    // 2. 发送GET请求
    println!("--- Sending GET request ---");
    let get_response = client.get("https://httpbin.org/get")
        .header("X-Custom-Header", "Rust")
        .send()
        .await?;
    
    println!("GET Response status: {}", get_response.status());
    println!("GET Body: {}", get_response.text().await?);

    // 3. 发送POST请求
    println!("\n--- Sending POST request ---");
    let mut post_data = HashMap::new();
    post_data.insert("name", "rquest");
    post_data.insert("version", "0.7");

    let post_response = client.post("https://httpbin.org/post")
        .json(&post_data)
        .send()
        .await?;
    
    println!("POST Response: {}", post_response.text().await?);

    // 4. 并发请求示例
    println!("\n--- Sending concurrent requests ---");
    let urls = vec![
        "https://httpbin.org/get?req=1",
        "https://httpbin.org/get?req=2",
        "https://httpbin.org/status/404",
    ];
    
    let requests = urls.into_iter().map(|url| {
        client.get(url).send()
    });
    
    let responses = join_all(requests).await;
    
    for response in responses {
        match response {
            Ok(res) => println!("Concurrent response status: {}", res.status()),
            Err(e) => println!("Error: {}", e),
        }
    }

    // 5. 错误处理示例
    println!("\n--- Error handling example ---");
    match client.get("https://httpbin.org/status/500").send().await {
        Ok(res) if res.status().is_success() => {
            println!("Request succeeded");
        }
        Ok(res) => {
            println!("Server returned error status: {}", res.status());
        }
        Err(Error::Timeout) => {
            eprintln!("Request timed out");
        }
        Err(e) => {
            eprintln!("Request failed: {}", e);
        }
    }

    Ok(())
}

示例说明

  1. 客户端配置

    • 设置了5秒超时
    • 添加了自定义的MetricsPlugin插件
  2. GET请求

    • 添加自定义header
    • 打印响应状态和内容
  3. POST请求

    • 发送JSON格式数据
    • 打印完整响应
  4. 并发请求

    • 使用join_all同时发送多个请求
    • 处理各个请求的结果
  5. 错误处理

    • 演示了不同错误类型的处理方式
    • 包括HTTP错误状态码的处理

这个完整示例展示了rquest库的主要功能:

  • 基本的HTTP请求(GET/POST)
  • 插件系统的使用
  • 并发请求处理
  • 详细的错误处理
  • 客户端配置选项

使用前请确保Cargo.toml中添加了正确的依赖:

[dependencies]
rquest = "0.7"
tokio = { version = "1.0", features = ["full"] }
async-trait = "0.1"
futures = "0.3"
回到顶部