Skip to main content

wae_https/response/
mod.rs

1//! HTTP 响应模块
2//!
3//! 提供统一的响应处理工具。
4
5use http::{Response, StatusCode, header};
6use serde::Serialize;
7use std::path::Path;
8
9use crate::{ApiResponse, Body, full_body};
10
11/// HTML 响应类型
12pub struct Html<T>(pub T);
13
14/// 重定向响应类型
15pub struct Redirect;
16
17/// 将类型转换为 HTTP 响应的 trait
18pub trait IntoResponse {
19    /// 将类型转换为 HTTP 响应
20    fn into_response(self) -> Response<Body>;
21}
22
23/// JSON 响应构建器
24pub struct JsonResponse;
25
26impl JsonResponse {
27    /// 返回成功响应
28    pub fn success<T: Serialize>(data: T) -> Response<Body> {
29        let api_response = ApiResponse::success(data);
30        let status = if api_response.success { StatusCode::OK } else { StatusCode::BAD_REQUEST };
31        let body = serde_json::to_string(&api_response).unwrap_or_default();
32        Response::builder().status(status).header(header::CONTENT_TYPE, "application/json").body(full_body(body)).unwrap()
33    }
34
35    /// 返回错误响应
36    pub fn error(code: impl Into<String>, message: impl Into<String>) -> Response<Body> {
37        let api_response = ApiResponse::<()>::error(code, message);
38        let status = if api_response.success { StatusCode::OK } else { StatusCode::BAD_REQUEST };
39        let body = serde_json::to_string(&api_response).unwrap_or_default();
40        Response::builder().status(status).header(header::CONTENT_TYPE, "application/json").body(full_body(body)).unwrap()
41    }
42
43    /// 返回 404 错误
44    pub fn not_found(message: impl Into<String>) -> Response<Body> {
45        let body = ApiResponse::<()>::error("NOT_FOUND", message);
46        Response::builder()
47            .status(StatusCode::NOT_FOUND)
48            .header(header::CONTENT_TYPE, "application/json")
49            .body(full_body(serde_json::to_string(&body).unwrap_or_default()))
50            .unwrap()
51    }
52
53    /// 返回 500 错误
54    pub fn internal_error(message: impl Into<String>) -> Response<Body> {
55        let body = ApiResponse::<()>::error("INTERNAL_ERROR", message);
56        Response::builder()
57            .status(StatusCode::INTERNAL_SERVER_ERROR)
58            .header(header::CONTENT_TYPE, "application/json")
59            .body(full_body(serde_json::to_string(&body).unwrap_or_default()))
60            .unwrap()
61    }
62}
63
64/// 附件响应
65///
66/// 用于创建文件下载响应。
67pub struct Attachment {
68    filename: String,
69    content_type: String,
70    data: Vec<u8>,
71}
72
73impl Attachment {
74    /// 创建新的附件响应
75    pub fn new(filename: impl Into<String>, content_type: impl Into<String>, data: Vec<u8>) -> Self {
76        Self { filename: filename.into(), content_type: content_type.into(), data }
77    }
78
79    /// 从文件路径创建附件响应
80    pub async fn from_path(path: impl AsRef<Path>, filename: Option<impl Into<String>>) -> std::io::Result<Self> {
81        let path = path.as_ref();
82        let data = tokio::fs::read(path).await?;
83        let filename = filename
84            .map(|f| f.into())
85            .unwrap_or_else(|| path.file_name().and_then(|n| n.to_str()).unwrap_or("download").to_string());
86        let content_type = mime_guess::from_path(path).first_or_octet_stream().to_string();
87        Ok(Self::new(filename, content_type, data))
88    }
89}
90
91impl IntoResponse for Attachment {
92    fn into_response(self) -> Response<Body> {
93        let disposition = format!("attachment; filename=\"{}\"", self.filename);
94        Response::builder()
95            .status(StatusCode::OK)
96            .header(header::CONTENT_TYPE, self.content_type)
97            .header(header::CONTENT_DISPOSITION, disposition)
98            .body(full_body(self.data))
99            .unwrap()
100    }
101}
102
103/// 流式响应
104///
105/// 用于创建流式数据响应。
106pub struct StreamResponse {
107    body: Body,
108    content_type: String,
109}
110
111impl StreamResponse {
112    /// 创建新的流式响应
113    pub fn new(body: Body, content_type: impl Into<String>) -> Self {
114        Self { body, content_type: content_type.into() }
115    }
116}
117
118impl IntoResponse for StreamResponse {
119    fn into_response(self) -> Response<Body> {
120        Response::builder().status(StatusCode::OK).header(header::CONTENT_TYPE, self.content_type).body(self.body).unwrap()
121    }
122}