引言:为什么要在Rust中编写HTTP客户端?
现代开发很少能不依赖与外部服务的交互。无论是天气REST API、数据库还是微服务架构——发送HTTP请求的能力都是一项基本技能。Rust以其对性能和安全的重视,提供了几种优雅的HTTP处理方案。在本文中,我们将探讨如何在Rust中正确创建HTTP客户端:从库的选择到复杂场景的处理。
我们将介绍两个最流行的库:reqwest(异步标准)和ureq(简单的同步方法)。您将学习如何发送GET和POST请求、处理JSON、管理标头以及避免常见错误。
1. 库的选择:reqwest vs ureq
在编写代码之前,需要确定使用哪个工具。Rust生态系统中有两个主要候选。
1.1. Reqwest——强大且异步
reqwest是Rust中HTTP请求的事实标准。它基于hyper和tokio构建,支持异步、自动JSON序列化/反序列化以及cookie处理。非常适合高负载应用和Web服务器。
首先,在Cargo.toml中添加:
[dependencies]reqwest = { version = "0.12", features = ["json"] }tokio = { version = "1", features = ["full"] }serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"1.2. Ureq——无需异步的简洁性
如果您不需要异步调用,并且正在编写简单的脚本或CLI工具,ureq将是一个很好的选择。它是同步的、极简的,并且不需要复杂的运行时配置。
[dependencies]ureq = "2.9"serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"何时选择哪个? 对于Web服务器和复杂应用——选择reqwest。对于简单任务、测试和脚本——选择ureq。
2. 基本请求:GET和POST
让我们看看两个库的实际示例。
2.1. 使用reqwest的GET请求
最简单的示例——从公共API获取数据。我们使用带有#[tokio::main]宏的异步main函数。
use reqwest;use std::error::Error;
#[tokio::main]async fn main() -> Result<(), Box<dyn Error>> { let url = "https://jsonplaceholder.typicode.com/posts/1"; let response = reqwest::get(url).await?;
// 检查响应状态 if response.status().is_success() { let body = response.text().await?; println!("响应: {}", body); } else { eprintln!("HTTP错误: {}", response.status()); }
Ok(())}2.2. 使用JSON体的POST请求(reqwest)
发送数据通常需要序列化结构体。为此,我们使用serde crate。
use reqwest;use serde::{Deserialize, Serialize};use std::error::Error;
#[derive(Serialize, Deserialize, Debug)]struct Post { title: String, body: String, user_id: i32,}
#[tokio::main]async fn main() -> Result<(), Box<dyn Error>> { let client = reqwest::Client::new(); let new_post = Post { title: "Hello Rust".to_string(), body: "这是请求体".to_string(), user_id: 1, };
let response = client .post("https://jsonplaceholder.typicode.com/posts") .json(&new_post) .send() .await?;
let created_post: Post = response.json().await?; println!("创建的帖子: {:?}", created_post);
Ok(())}2.3. 使用ureq的简单GET请求
使用ureq,代码变得更短,因为它不需要异步:
use ureq;use std::error::Error;
fn