qiniu_upload/
error.rs

1use reqwest::{
2    blocking::Response,
3    header::{HeaderName, HeaderValue},
4    Error as ReqwestError, StatusCode,
5};
6use serde::{de::DeserializeOwned, Deserialize};
7use serde_json::Error as JSONError;
8use std::{error::Error, fmt, io::Error as IOError};
9use thiserror::Error;
10use url::ParseError as URLParseError;
11
12/// HTTP 调用错误
13#[derive(Error, Debug)]
14#[non_exhaustive]
15pub enum HttpCallError {
16    /// 本地 IO 错误
17    #[error("Local IO error: {0}")]
18    LocalIoError(#[from] IOError),
19
20    /// 非法的 URL
21    #[error("Invalid URL error: {0}")]
22    InvalidUrl(#[from] URLParseError),
23
24    /// Reqwest 库调用错误
25    #[error("HTTP Call error: {0}")]
26    ReqwestError(#[from] ReqwestError),
27
28    /// JSON 解析错误
29    #[error("JSON decode error: {0}")]
30    JsonDecodeError(#[from] JsonDecodeError),
31
32    /// 状态码错误
33    #[error("HTTP Status Code error: {0}")]
34    StatusCodeError(#[from] StatusCodeError),
35}
36/// HTTP 调用结果
37pub type HttpCallResult<T> = Result<T, HttpCallError>;
38
39/// JSON 解析错误
40#[derive(Debug)]
41pub struct JsonDecodeError {
42    error: JSONError,
43    status_code: StatusCode,
44    request_id: Option<HeaderValue>,
45}
46
47impl JsonDecodeError {
48    pub(super) fn new(
49        error: JSONError,
50        status_code: StatusCode,
51        request_id: Option<HeaderValue>,
52    ) -> Self {
53        Self {
54            error,
55            status_code,
56            request_id,
57        }
58    }
59
60    /// 获取核心错误信息
61    #[inline]
62    pub fn error(&self) -> &JSONError {
63        &self.error
64    }
65
66    /// 获取错误状态码
67    #[inline]
68    pub fn status_code(&self) -> StatusCode {
69        self.status_code
70    }
71
72    /// 获取请求 ID
73    #[inline]
74    pub fn request_id(&self) -> Option<&HeaderValue> {
75        self.request_id.as_ref()
76    }
77}
78
79impl fmt::Display for JsonDecodeError {
80    #[inline]
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        write!(
83            f,
84            "message: {}, status_code: {}",
85            self.error, self.status_code
86        )?;
87        if let Some(request_id) = &self.request_id {
88            write!(f, ", request_id: {:?}", request_id)?;
89        }
90        Ok(())
91    }
92}
93
94impl Error for JsonDecodeError {
95    #[inline]
96    fn source(&self) -> Option<&(dyn Error + 'static)> {
97        Some(&self.error)
98    }
99}
100
101/// 状态码错误
102#[derive(Debug)]
103pub struct StatusCodeError {
104    status_code: StatusCode,
105    error_message: Option<Box<str>>,
106    request_id: Option<HeaderValue>,
107}
108
109impl StatusCodeError {
110    #[inline]
111    pub(super) fn new(
112        status_code: StatusCode,
113        error_message: Option<Box<str>>,
114        request_id: Option<HeaderValue>,
115    ) -> Self {
116        Self {
117            status_code,
118            error_message,
119            request_id,
120        }
121    }
122
123    /// 获取错误状态码
124    #[inline]
125    pub fn status_code(&self) -> StatusCode {
126        self.status_code
127    }
128
129    /// 获取错误信息
130    #[inline]
131    pub fn error_message(&self) -> Option<&str> {
132        self.error_message.as_deref()
133    }
134
135    /// 获取请求 ID
136    #[inline]
137    pub fn request_id(&self) -> Option<&HeaderValue> {
138        self.request_id.as_ref()
139    }
140}
141
142impl fmt::Display for StatusCodeError {
143    #[inline]
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        write!(f, "status_code: {}", self.status_code)?;
146        if let Some(error_message) = &self.error_message {
147            write!(f, ", error_message: {}", error_message)?;
148        }
149        if let Some(request_id) = &self.request_id {
150            write!(f, ", request_id: {:?}", request_id)?;
151        }
152        Ok(())
153    }
154}
155
156impl Error for StatusCodeError {}
157
158const X_REQ_ID: &str = "x-reqid";
159
160impl From<Response> for HttpCallError {
161    #[inline]
162    fn from(response: Response) -> Self {
163        #[derive(Debug, Clone, Deserialize)]
164        struct ErrorBody {
165            error: Option<Box<str>>,
166        }
167
168        let status_code = response.status();
169        let request_id = response
170            .headers()
171            .get(HeaderName::from_static(X_REQ_ID))
172            .cloned();
173
174        match serde_json::from_reader::<_, ErrorBody>(response) {
175            Ok(error_body) => Self::StatusCodeError(StatusCodeError {
176                status_code,
177                request_id,
178                error_message: error_body.error,
179            }),
180            Err(error) => Self::JsonDecodeError(JsonDecodeError {
181                error,
182                status_code,
183                request_id,
184            }),
185        }
186    }
187}
188
189pub(super) fn json_decode_response<T: DeserializeOwned>(
190    response: Response,
191) -> HttpCallResult<(T, Option<HeaderValue>)> {
192    let status_code = response.status();
193    let request_id = response
194        .headers()
195        .get(HeaderName::from_static(X_REQ_ID))
196        .cloned();
197    match serde_json::from_reader::<_, T>(response) {
198        Ok(body) => Ok((body, request_id)),
199        Err(error) => Err(HttpCallError::JsonDecodeError(JsonDecodeError {
200            error,
201            status_code,
202            request_id,
203        })),
204    }
205}