You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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自动生成错误类型的相关实现,步骤如下:

  1. 在Cargo.toml中添加依赖:thiserror = "1.0"
  2. 定义枚举类型的错误:
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 },
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 21:45:02