Skip to main content

framework_web/
response.rs

1use crate::{WebError, WebErrorKind, WebRequest};
2use anyhow::{Error, Result};
3use bytes::Bytes;
4use framework_core::MultiStringValue;
5use framework_core::types::R;
6use futures_util::stream::BoxStream;
7use serde::Serialize;
8use serde_json::json;
9use std::marker::PhantomData;
10use std::ops::{Deref, DerefMut};
11
12const INTERNAL_ERROR_BODY: &[u8] = br#"{"code":500,"message":"Server Error"}"#;
13
14/// 响应体:一次性字节内容或持续输出的流。
15pub enum WebBody {
16    /// 一次性返回的字节内容。
17    Bytes(Bytes),
18    /// 流式返回的内容,用于 SSE 等场景。
19    Stream(BoxStream<'static, Result<Bytes, std::io::Error>>),
20}
21
22impl WebBody {
23    /// 是否为流式响应体。
24    pub fn is_stream(&self) -> bool {
25        matches!(self, Self::Stream(_))
26    }
27}
28
29impl Default for WebBody {
30    fn default() -> Self {
31        Self::Bytes(Bytes::new())
32    }
33}
34
35impl From<Bytes> for WebBody {
36    fn from(value: Bytes) -> Self {
37        Self::Bytes(value)
38    }
39}
40
41impl From<Vec<u8>> for WebBody {
42    fn from(value: Vec<u8>) -> Self {
43        Self::Bytes(Bytes::from(value))
44    }
45}
46
47impl From<String> for WebBody {
48    fn from(value: String) -> Self {
49        Self::Bytes(Bytes::from(value))
50    }
51}
52
53impl From<BoxStream<'static, Result<Bytes, std::io::Error>>> for WebBody {
54    fn from(value: BoxStream<'static, Result<Bytes, std::io::Error>>) -> Self {
55        Self::Stream(value)
56    }
57}
58
59pub struct WebResponse {
60    pub status: u16,
61    pub headers: MultiStringValue,
62    pub body: WebBody,
63}
64
65/// 声明载荷类型的 [`WebResponse`] 包装。
66///
67/// 运行时行为与 [`WebResponse`] 完全一致,状态码、响应头与响应体通过 [`Deref`] / [`DerefMut`]
68/// 直接访问。仅用于让 `web_api*` / `ts_api` 宏在显式构造 `WebResponse`(自定义响应头、
69/// 状态码等)时推导出实际载荷类型,从而导出准确的 TypeScript 返回类型。
70/// 仅返回二进制或流式响应时仍直接使用 `WebResponse`。
71pub struct WebResponseOf<T> {
72    response: WebResponse,
73    payload: PhantomData<fn() -> T>,
74}
75
76impl<T> WebResponseOf<T> {
77    /// 序列化载荷并构造 200 响应。
78    pub fn from_t(value: T, request: Option<&WebRequest>) -> Self
79    where
80        T: Serialize,
81    {
82        Self::from_response(WebResponse::from_t(value, request))
83    }
84
85    /// 序列化载荷结果并构造响应,失败时返回错误响应。
86    pub fn from_result_t(result: Result<T>, request: Option<&WebRequest>) -> Self
87    where
88        T: Serialize,
89    {
90        Self::from_response(WebResponse::from_result_t(result, request))
91    }
92
93    /// 包装已构造的响应。
94    pub fn from_response(response: WebResponse) -> Self {
95        Self {
96            response,
97            payload: PhantomData,
98        }
99    }
100
101    /// 取出底层响应。
102    pub fn into_response(self) -> WebResponse {
103        self.response
104    }
105}
106
107impl<T> Deref for WebResponseOf<T> {
108    type Target = WebResponse;
109
110    fn deref(&self) -> &Self::Target {
111        &self.response
112    }
113}
114
115impl<T> DerefMut for WebResponseOf<T> {
116    fn deref_mut(&mut self) -> &mut Self::Target {
117        &mut self.response
118    }
119}
120
121impl WebResponse {
122    pub fn empty() -> Self {
123        Self {
124            status: 204,
125            headers: MultiStringValue::default(),
126            body: WebBody::Bytes(Bytes::new()),
127        }
128    }
129
130    pub fn from_error(error: Error, request: Option<&WebRequest>) -> Self {
131        let error = normalize_error(error);
132        WebError::log(&error, request);
133        Self::error_body(&error)
134    }
135
136    pub fn from_error_request(error: Error, trace_id: &str, method: &str, path: &str) -> Self {
137        let error = normalize_error(error);
138        WebError::log_request(&error, trace_id, method, path);
139        Self::error_body(&error)
140    }
141
142    fn error_body(error: &WebError) -> Self {
143        let status = error.status();
144        let message = error.public_message();
145        Self::json(status, &json!({ "code": status, "message": message }))
146    }
147
148    pub fn from_result(result: Result<Self>, request: Option<&WebRequest>) -> Self {
149        match result {
150            Ok(response) => response,
151            Err(error) => Self::from_error(error, request),
152        }
153    }
154
155    pub fn from_t<T>(value: T, request: Option<&WebRequest>) -> Self
156    where
157        T: Serialize,
158    {
159        let r = R::ok(value);
160        Self::serialize(&r, request)
161    }
162
163    pub fn from_r<T>(value: R<T>, request: Option<&WebRequest>) -> Self
164    where
165        T: Serialize,
166    {
167        Self::serialize(&value, request)
168    }
169
170    pub fn from_result_t<T>(result: Result<T>, request: Option<&WebRequest>) -> Self
171    where
172        T: Serialize,
173    {
174        match result {
175            Ok(value) => Self::from_t(value, request),
176            Err(error) => Self::from_error(error, request),
177        }
178    }
179
180    pub fn from_result_r<T>(result: Result<R<T>>, request: Option<&WebRequest>) -> Self
181    where
182        T: Serialize,
183    {
184        match result {
185            Ok(value) => Self::from_r(value, request),
186            Err(error) => Self::from_error(error, request),
187        }
188    }
189
190    fn serialize<T>(value: &T, request: Option<&WebRequest>) -> Self
191    where
192        T: Serialize,
193    {
194        match serde_json::to_vec(value) {
195            Ok(body) => Self::json_bytes(200, body),
196            Err(error) => Self::from_error(
197                Error::from(WebError::return_conversion("返回值 JSON 序列化失败", error)),
198                request,
199            ),
200        }
201    }
202
203    fn json<T>(status: u16, value: &T) -> Self
204    where
205        T: Serialize,
206    {
207        match serde_json::to_vec(value) {
208            Ok(body) => Self::json_bytes(status, body),
209            Err(_) => Self::json_bytes(500, INTERNAL_ERROR_BODY.to_vec()),
210        }
211    }
212
213    fn json_bytes(status: u16, body: Vec<u8>) -> Self {
214        let mut headers = MultiStringValue::default();
215        headers.set_content_type("application/json; charset=utf-8");
216        headers.set_content_length(body.len());
217        Self {
218            status,
219            headers,
220            body: WebBody::Bytes(Bytes::from(body)),
221        }
222    }
223
224    /// 构造流式响应,用于 SSE 等持续输出场景。
225    pub fn stream(
226        status: u16,
227        content_type: &str,
228        stream: BoxStream<'static, Result<Bytes, std::io::Error>>,
229    ) -> Self {
230        let mut headers = MultiStringValue::default();
231        headers.set_content_type(content_type);
232        Self {
233            status,
234            headers,
235            body: WebBody::Stream(stream),
236        }
237    }
238}
239
240fn normalize_error(error: Error) -> WebError {
241    error.downcast::<WebError>().unwrap_or_else(|error| {
242        if let Some(message) = error.downcast_ref::<&'static str>() {
243            WebError::with_source(WebErrorKind::Message, *message, error)
244        } else if let Some(message) = error.downcast_ref::<String>() {
245            WebError::with_source(WebErrorKind::Message, message.clone(), error)
246        } else {
247            WebError::internal("请求处理发生内部错误", error)
248        }
249    })
250}