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.body(Body::from(body)).unwrap()
61	}
62}
63
64// 为 StatusCode 实现(仅状态码)
65impl IntoResponse for StatusCode {
66	fn into_response(self) -> Response<Body> {
67		Response::builder()
68			.status(self)
69			.body(Body::empty())
70			.unwrap()
71	}
72}
73
74/// JSON 响应包装器
75pub struct Json<T: Serialize>(pub T);
76
77impl<T: Serialize> IntoResponse for Json<T> {
78	fn into_response(self) -> Response<Body> {
79		let json = serde_json::to_string(&self.0).unwrap();
80		Response::builder()
81			.header(header::CONTENT_TYPE, "application/json")
82			.body(Body::from(json))
83			.unwrap()
84	}
85}
86
87/// HTML 响应包装器
88pub struct Html(pub String);
89
90impl IntoResponse for Html {
91	fn into_response(self) -> Response<Body> {
92		Response::builder()
93			.header(header::CONTENT_TYPE, "text/html; charset=utf-8")
94			.body(Body::from(self.0))
95			.unwrap()
96	}
97}
98
99/// 文本响应包装器
100pub struct Text(pub String);
101
102impl IntoResponse for Text {
103	fn into_response(self) -> Response<Body> {
104		Response::builder()
105			.header(header::CONTENT_TYPE, "text/plain; charset=utf-8")
106			.body(Body::from(self.0))
107			.unwrap()
108	}
109}
110
111// 为 Result 实现
112impl<T, E> IntoResponse for Result<T, E>
113where
114	T: IntoResponse,
115	E: IntoResponse,
116{
117	fn into_response(self) -> Response<Body> {
118		match self {
119			Ok(value) => value.into_response(),
120			Err(err) => err.into_response(),
121		}
122	}
123}
124
125// 重定向url包装器
126pub struct Redirect(pub String);
127
128impl IntoResponse for Redirect {
129	fn into_response(self) -> Response<Body> {
130		Response::builder()
131			.status(302)
132			.header("Location", self.0)
133			.body(Body::empty())
134			.unwrap()
135	}
136}
137
138// 永久重定向url包装器
139pub struct PermRedirect(pub String);
140
141impl IntoResponse for PermRedirect {
142	fn into_response(self) -> Response<Body> {
143		Response::builder()
144			.status(301)
145			.header("Location", self.0)
146			.body(Body::empty())
147			.unwrap()
148	}
149}
150
151impl Redirect {
152	pub fn perm(url: String) -> PermRedirect {
153		PermRedirect(url)
154	}
155}
156
157// 文件包装器
158pub struct File(pub String, pub bool);
159
160impl IntoResponse for File {
161	fn into_response(self) -> Response<Body> {
162		Response::builder()
163			.header(
164				header::CONTENT_TYPE,
165				if self.1 {
166					"application/octet-stream; charset=utf-8".to_string()
167				} else {
168					format!(
169						"{}; charset=utf-8",
170						get_mine_from_path(&self.0)
171							.first_or_octet_stream()
172							.to_string()
173					)
174				},
175			)
176			.body(Body::from(read_file(self.0).unwrap_or(String::new())))
177			.unwrap()
178	}
179}