如何在reqwest返回非200状态码时触发错误(Rust)
处理Rust中reqwest的API状态码错误
先修正原代码的一个小问题
你当前代码里的header("X-Api-Key", "os_api_key")是传入了字符串字面量"os_api_key",而非你读取的环境变量值,需要改成header("X-Api-Key", &os_api_key)才能正确传递API密钥。
自定义错误类型的简化实现
你之前手动实现APIError的方式可以简化,Rust 1.31+之后,Error trait只要求实现Debug和Display即可,无需再实现已废弃的description方法:
use std::fmt; use std::error::Error; #[derive(Debug)] pub struct APIError { status_code: u16, details: String, } // 自动推导Error trait实现,只要有Debug和Display impl Error for APIError {} impl fmt::Display for APIError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "API请求失败,状态码: {},详情: {}", self.status_code, self.details) } }
在API调用中触发自定义错误
修改make_api_call函数,在获取响应后检查状态码,非成功状态则返回自定义错误,同时处理reqwest本身的网络错误:
async fn make_api_call(endpoint: &str) -> Result<reqwest::Response, APIError> { let client = reqwest::Client::new(); dotenv::dotenv().ok(); let os_request_url = std::env::var("OS_REQUEST_URL").expect("os_request_url must be set."); let os_api_key = std::env::var("OS_API_KEY").expect("os_api_key must be set."); // 处理reqwest的网络错误,转换为自定义APIError let client_response = client .get(format!("{os_request_url}{endpoint}")) .header("X-Api-Key", &os_api_key) .header(reqwest::header::ACCEPT, "application/json") .send() .await .map_err(|e| APIError { status_code: 0, // 网络错误无HTTP状态码,用0标记 details: format!("请求发送失败: {}", e), })?; let status = client_response.status(); // 检查状态码是否为2xx成功状态 if !status.is_success() { // 尝试读取响应体作为错误详情,读取失败则用默认文本 let details = client_response.text().await.unwrap_or_else(|_| "无法获取错误详情".to_string()); return Err(APIError { status_code: status.as_u16(), details, }); } Ok(client_response) }
更简洁的错误处理方案(使用thiserror)
如果觉得手动实现错误类型繁琐,可以用thiserror crate自动生成错误类型的相关实现,步骤如下:
- 在
Cargo.toml中添加依赖:thiserror = "1.0" - 定义枚举类型的错误:
use thiserror::Error; #[derive(Error, Debug)] pub enum APIError { // 自动将reqwest::Error转换为APIError::RequestError #[error("网络请求失败: {0}")] RequestError(#[from] reqwest::Error), // 自定义响应错误,包含状态码和详情 #[error("API响应错误,状态码: {status_code},详情: {details}")] ResponseError { status_code: u16, details: String }, }
- 修改API调用函数,无需手动转换reqwest错误:
async fn make_api_call(endpoint: &str) -> Result<reqwest::Response, APIError> { let client = reqwest::Client::new(); dotenv::dotenv().ok(); let os_request_url = std::env::var("OS_REQUEST_URL").expect("os_request_url must be set."); let os_api_key = std::env::var("OS_API_KEY").expect("os_api_key must be set."); let client_response = client .get(format!("{os_request_url}{endpoint}")) .header("X-Api-Key", &os_api_key) .header(reqwest::header::ACCEPT, "application/json") .send() .await?; // 直接用?自动转换reqwest错误 let status = client_response.status(); if !status.is_success() { let details = client_response.text().await.unwrap_or_else(|_| "无法获取错误详情".to_string()); return Err(APIError::ResponseError { status_code: status.as_u16(), details, }); } Ok(client_response) }
内容的提问来源于stack exchange,提问作者Omar Mir
相关产品推荐
相关产品推荐

