From 5c48a5d548c730a3cf962c17042ed51f9dc10c10 Mon Sep 17 00:00:00 2001 From: Hubert Shelley <46239302+hubertshelley@users.noreply.github.com> Date: Wed, 30 Apr 2025 16:29:41 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20www=5Fform=5Furlencoded=E5=8F=8D?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E5=BC=82=E5=B8=B8=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/form/src/main.rs | 10 +++--- examples/get_real_ip/src/main.rs | 4 +-- examples/sse-chat/src/main.rs | 4 +-- examples/todo/src/main.rs | 4 +-- silent/src/core/request.rs | 61 ++++++++++++++++++++------------ silent/src/error/mod.rs | 5 ++- 6 files changed, 53 insertions(+), 35 deletions(-) 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,