diff --git a/examples/form/src/main.rs b/examples/form/src/main.rs index dbb4a53..10519df 100644 --- a/examples/form/src/main.rs +++ b/examples/form/src/main.rs @@ -14,12 +14,13 @@ struct Input { email: String, } -async fn accept_form(mut req: Request) -> Result> { +async fn accept_form(mut req: Request) -> Result { req.json_parse().await } -async fn show_form(_req: Request) -> Result<&'static str> { - Ok(r#" +async fn show_form(_req: Request) -> Result { + Ok(Response::html( + r#" @@ -39,5 +40,6 @@ async fn show_form(_req: Request) -> Result<&'static str> { - "#) + "#, + )) } diff --git a/examples/get_real_ip/src/main.rs b/examples/get_real_ip/src/main.rs index d1e6669..85438f3 100644 --- a/examples/get_real_ip/src/main.rs +++ b/examples/get_real_ip/src/main.rs @@ -3,7 +3,5 @@ use silent::prelude::*; fn main() { logger::fmt().with_max_level(Level::INFO).init(); let route = Route::new("").get(|req| async move { Ok(req.remote().to_string()) }); - Server::new() - .bind("0.0.0.0:8000".parse().unwrap()) - .run(route); + Server::new().run(route); } diff --git a/examples/sse-chat/src/main.rs b/examples/sse-chat/src/main.rs index f50ada1..ba8fe94 100644 --- a/examples/sse-chat/src/main.rs +++ b/examples/sse-chat/src/main.rs @@ -9,7 +9,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use futures_util::StreamExt; use once_cell::sync::Lazy; use parking_lot::Mutex; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use tokio::sync::mpsc; use tokio_stream::wrappers::UnboundedReceiverStream; @@ -40,7 +40,7 @@ enum Message { Reply(String), } -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, Serialize)] struct Msg { msg: String, } diff --git a/examples/todo/src/main.rs b/examples/todo/src/main.rs index 2cb987e..deb7c1a 100644 --- a/examples/todo/src/main.rs +++ b/examples/todo/src/main.rs @@ -56,7 +56,7 @@ async fn todos_index(mut req: Request) -> Result> { Ok(todos) } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize)] struct CreateTodo { text: String, } @@ -76,7 +76,7 @@ async fn todos_create(mut req: Request) -> Result { Ok(todo) } -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize)] struct UpdateTodo { text: Option, completed: Option, diff --git a/silent/src/core/request.rs b/silent/src/core/request.rs index 713ee62..794f3c7 100644 --- a/silent/src/core/request.rs +++ b/silent/src/core/request.rs @@ -13,8 +13,8 @@ use http::{Extensions, HeaderMap, HeaderValue, Method, Uri, Version}; use http::{Request as BaseRequest, StatusCode}; use http_body_util::BodyExt; use mime::Mime; -use serde::Deserialize; use serde::de::StdError; +use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; use tokio::sync::OnceCell; @@ -293,7 +293,9 @@ impl Request { #[cfg(feature = "multipart")] #[inline] pub async fn form_data(&mut self) -> Result<&FormData> { - let content_type = self.content_type().ok_or(SilentError::ContentTypeError)?; + let content_type = self + .content_type() + .ok_or(SilentError::ContentTypeMissingError)?; if content_type.subtype() != mime::FORM_DATA { return Err(SilentError::ContentTypeError); } @@ -343,17 +345,22 @@ impl Request { pub async fn json_parse(&mut self) -> Result where for<'de> T: Deserialize<'de>, + T: Serialize, { let body = self.take_body(); - let content_type = self.content_type().ok_or(SilentError::ContentTypeError)?; - if content_type.subtype() != mime::JSON { + let content_type = self + .content_type() + .ok_or(SilentError::ContentTypeMissingError)?; + if content_type.subtype() != mime::JSON + && content_type.subtype() != mime::WWW_FORM_URLENCODED + { return Err(SilentError::ContentTypeError); } - match body { - ReqBody::Incoming(body) => { - let value = self - .json_data - .get_or_try_init(|| async { + let value = self + .json_data + .get_or_try_init(|| async { + let value = match body { + ReqBody::Incoming(body) => { let bytes = body .collect() .await @@ -362,20 +369,28 @@ impl Request { if bytes.is_empty() { return Err(SilentError::JsonEmpty); } - serde_json::from_slice(&bytes).map_err(|e| e.into()) - }) - .await?; - Ok(serde_json::from_value(value.to_owned())?) - } - ReqBody::Once(bytes) => match content_type.subtype() { - mime::WWW_FORM_URLENCODED => { - serde_html_form::from_bytes(&bytes).map_err(SilentError::from) - } - mime::JSON => serde_json::from_slice(&bytes).map_err(|e| e.into()), - _ => Err(SilentError::JsonEmpty), - }, - ReqBody::Empty => Err(SilentError::BodyEmpty), - } + match content_type.subtype() { + mime::WWW_FORM_URLENCODED => { + serde_html_form::from_bytes::(&bytes).map_err(SilentError::from) + } + mime::JSON => serde_json::from_slice::(&bytes).map_err(|e| e.into()), + _ => Err(SilentError::JsonEmpty), + } + } + ReqBody::Once(bytes) => match content_type.subtype() { + mime::WWW_FORM_URLENCODED => { + serde_html_form::from_bytes(&bytes).map_err(SilentError::from) + } + mime::JSON => serde_json::from_slice(&bytes).map_err(|e| e.into()), + _ => Err(SilentError::JsonEmpty), + }, + ReqBody::Empty => Err(SilentError::BodyEmpty), + }?; + serde_json::to_value(&value).map_err(|e| e.into()) + }) + .await? + .clone(); + serde_json::from_value(value).map_err(Into::into) } /// 转换body参数按Json匹配 diff --git a/silent/src/error/mod.rs b/silent/src/error/mod.rs index 6d78dd8..f0fc072 100644 --- a/silent/src/error/mod.rs +++ b/silent/src/error/mod.rs @@ -38,9 +38,12 @@ pub enum SilentError { /// Json为空 错误 #[error("json is empty")] JsonEmpty, - /// Json为空 错误 + /// Content-Type 错误 #[error("content-type is error")] ContentTypeError, + /// Content-Type 缺失错误 + #[error("content-type is missing")] + ContentTypeMissingError, /// Params为空 错误 #[error("params is empty")] ParamsEmpty,