Skip to main content

nimble_http/
response.rs

1//! response.rs
2
3use hyper::{Body, Response, StatusCode, header};
4use mime_guess::from_path as get_mine_from_path;
5use serde::Serialize;
6use std::fs::read_to_string as read_file;
7
8/// 转换为 HTTP 响应的 trait
9pub trait IntoResponse {
10	fn into_response(self) -> Response<Body>;
11}
12
13// 为 &str 实现
14impl IntoResponse for &'static str {
15	fn into_response(self) -> Response<Body> {
16		Response::builder()
17			.header(header::CONTENT_TYPE, "text/plain; charset=utf-8")
18			.body(Body::from(self))
19			.unwrap()
20	}
21}
22
23// 为 String 实现
24impl IntoResponse for String {
25	fn into_response(self) -> Response<Body> {
26		Response::builder()
27			.header(header::CONTENT_TYPE, "text/plain; charset=utf-8")
28			.body(Body::from(self))
29			.unwrap()
30	}
31}
32
33// 为 Vec<u8> 实现
34impl IntoResponse for Vec<u8> {
35	fn into_response(self) -> Response<Body> {
36		Response::builder().body(Body::from(self)).unwrap()
37	}
38}
39
40// 为 () 实现(空响应)
41impl IntoResponse for () {
42	fn into_response(self) -> Response<Body> {
43		Response::builder()
44			.status(StatusCode::NO_CONTENT)
45			.body(Body::empty())
46			.unwrap()
47	}
48}
49
50// 为 ([header1,header2...], String) 实现
51impl<const N: usize> IntoResponse for ([(header::HeaderName, &'static str); N], String) {
52	fn into_response(self) -> Response<Body> {
53		let (headers, body) = self;
54		let mut builder = Response::builder();
55		
56		for (name, value) in headers {
57			builder = builder.header(name, value);
58		}
59		
60		builder
61			.body(Body::from(body))
62			.unwrap()
63	}
64}
65
66// 为 StatusCode 实现(仅状态码)
67impl IntoResponse for StatusCode {
68	fn into_response(self) -> Response<Body> {
69		Response::builder()
70			.status(self)
71			.body(Body::empty())
72			.unwrap()
73	}
74}
75
76/// JSON 响应包装器
77pub struct Json<T: Serialize>(pub T);
78
79impl<T: Serialize> IntoResponse for Json<T> {
80	fn into_response(self) -> Response<Body> {
81		let json = serde_json::to_string(&self.0).unwrap();
82		Response::builder()
83			.header(header::CONTENT_TYPE, "application/json")
84			.body(Body::from(json))
85			.unwrap()
86	}
87}
88
89/// HTML 响应包装器
90pub struct Html(pub String);
91
92impl IntoResponse for Html {
93	fn into_response(self) -> Response<Body> {
94		Response::builder()
95			.header(header::CONTENT_TYPE, "text/html; charset=utf-8")
96			.body(Body::from(self.0))
97			.unwrap()
98	}
99}
100
101/// 文本响应包装器
102pub struct Text(pub String);
103
104impl IntoResponse for Text {
105	fn into_response(self) -> Response<Body> {
106		Response::builder()
107			.header(header::CONTENT_TYPE, "text/plain; charset=utf-8")
108			.body(Body::from(self.0))
109			.unwrap()
110	}
111}
112
113// 为 Result 实现
114impl<T, E> IntoResponse for Result<T, E>
115where
116	T: IntoResponse,
117	E: IntoResponse,
118{
119	fn into_response(self) -> Response<Body> {
120		match self {
121			Ok(value) => value.into_response(),
122			Err(err) => err.into_response(),
123		}
124	}
125}
126
127// 重定向url包装器
128pub struct Redirect(pub String);
129
130impl IntoResponse for Redirect {
131	fn into_response(self) -> Response<Body> {
132        Response::builder()
133            .status(302)
134            .header("Location", self.0)
135            .body(Body::empty())
136            .unwrap()
137	}
138}
139
140// 永久重定向url包装器
141pub struct PermRedirect(pub String);
142
143impl IntoResponse for PermRedirect {
144    fn into_response(self) -> Response<Body> {
145        Response::builder()
146            .status(301)
147            .header("Location", self.0)
148            .body(Body::empty())
149            .unwrap()
150    }
151}
152
153impl Redirect {
154	pub fn perm(url: String) -> PermRedirect {
155		PermRedirect(url)
156	}
157}
158
159// 文件包装器
160pub struct File(pub String, pub bool);
161
162impl IntoResponse for File {
163	fn into_response(self) -> Response<Body> {
164		Response::builder()
165			.header(
166				header::CONTENT_TYPE,
167				if self.1 {
168					"application/octet-stream; charset=utf-8".to_string()
169				} else {
170					format!(
171						"{}; charset=utf-8",
172						get_mine_from_path(&self.0)
173							.first_or_octet_stream()
174							.to_string()
175					)
176				},
177			)
178			.body(Body::from(read_file(self.0).unwrap_or(String::new())))
179			.unwrap()
180	}
181}