最近使用rust web框架salvo练习rust,为了巩固学习成果,总结一下如何使用salvo解析请求数据。项目如何搭建,可以查看salvo搭建rust web项目。
也欢迎小伙伴来github上下载hello_salvo一起练习rust,觉得不错的话,给一个小星星哟!
GET请求
- 从请求url中取参数
// "/user/<id>?oid={order_id}" #[handler] async fn query_order_in_user(req: &mut Request, res: &mut Response) { // 从路径上取参数 let user_id = req.param::<String>("id").unwrap(); // 从?后面取参数 let order_id = req.query::<String>("oid").unwrap(); // 写出响应数据 res.render(format!("user_id:{}\norder_id:{}", user_id, order_id)); } 复制代码
- 实体类接收
#[derive(Debug, Serialize, Deserialize, Extractible)] struct OrderQuery { // 从请求路径中解析,别名是“id” #[extract(alias = "id", source(from = "param"))] user_id: String, // 从?后面解析,别名是“oid” #[extract(alias = "oid", source(from = "query"))] order_id: String, } // /user/<id>?oid={order_id} #[handler] async fn query_order_in_user(query: OrderQuery, res: &mut Response) { // 从路径上取参数 let user_id = query.user_id; // 从?后面取参数 let order_id = query.order_id; // 写出响应数据 res.render(format!("user_id:{}\norder_id:{}", user_id, order_id)); } 复制代码
- Router编写方式:
Router::with_path("/user/<id>").get(query_order_in_user) 复制代码
POST请求
先定义UserInfo结构体用来接收数据
#[derive(Debug, Serialize, Deserialize, Extractible)] #[extract( default_source(from = "body", format = "json") )] struct UserInfo { pub account: String, pub password: String, } 复制代码
- 从请求体中解析数据
#[handler] async fn create_account(req: &mut Request) -> Result<String, GlobalError> { // 从请求体中解析参数并创建UserInfo对象 let user_info: UserInfo = req.extract_body().await.unwrap(); // 取出数据 let account = &user_info.account; let password = &user_info.password; // 调用业务逻辑 match AccountService::add_account(account, password) { Ok(x) => { info!("受影响的行数:{}", x); Ok(String::from("成功!")) } Err(e) => Err(e) } } 复制代码
- 实体类接收数据
// 自动从请求中取数据并实例化UserInfo对象 #[handler] async fn create_account(user_info: UserInfo) -> Result<String, GlobalError> { let account = &user_info.account; let password = &user_info.password; match AccountService::add_account(account, password) { Ok(x) => { info!("受影响的行数:{}", x); Ok(String::from("成功!")) } Err(e) => Err(e) } } 复制代码
- Router的编写方式:
Router::with_path("/create_account").post(create_account) 复制代码
- 发生请求的方式:
curl -X "POST" "http://127.0.0.1:7878/create_account" \ -H 'Content-Type: application/json; charset=utf-8' \ -d $'{ "account": "helloworld", "password": "123456" }' 复制代码
- 同时从请求路径,url参数和请求体中取数据
#[derive(Debug, Serialize, Deserialize, Extractible)] struct OrderSave { // 从请求路径中取参数"id"的值 #[extract(alias = "id", source(from = "param"))] user_id: String, // 从?后面取参数"oid"的值 #[extract(alias = "oid", source(from = "query"))] order_id: String, // 从请求体中取数据 #[extract(source(from = "body", format = "json"))] title: String, #[extract(source(from = "body", format = "json"))] price: f64, } #[handler] async fn edit_order(order_save: OrderSave, res: &mut Response) { // 直接把解析好的数据输出到响应中 res.render(Json(order_save)); } 复制代码
- Router编写方式:
Router::with_path("/user/<id>").post(edit_order) 复制代码
- 请求方式:
curl -X "POST" "http://127.0.0.1:7878/user/123456?oid=order_123456" \ -H 'Content-Type: application/json; charset=utf-8' \ -d $'{ "title": "标题", "price": 18.88 }' 复制代码
- 从请求头中取数据
#[derive(Debug, Serialize, Deserialize, Extractible)] struct OrderSave { // 从请求路径中取参数"id"的值 #[extract(alias = "id", source(from = "param"))] user_id: String, // 从?后面取参数"oid"的值 #[extract(alias = "oid", source(from = "query"))] order_id: String, // 从请求体中取值 #[extract(alias = "Cookie", source(from = "header"))] cookie:String, // 从请求体中取数据 #[extract(source(from = "body", format = "json"))] title: String, #[extract(source(from = "body", format = "json"))] price: f64, } #[handler] async fn edit_order(order_save: OrderSave, req: &mut Request, res: &mut Response) { // 需要注意的是,参数中中划线的参数在实体类中暂时解析不出来,需要单独拎出来解析 let content_type: String = req.header("Content-Type").unwrap(); println!("{}", content_type); res.render(Json(order_save)); } 复制代码
- Router编写方式:
Router::with_path("/user/<id>").post(edit_order) 复制代码
- 请求方式:
curl -X "POST" "http://127.0.0.1:7878/user/123456?oid=order_123456" \ -H 'Content-Type: application/json; charset=utf-8' \ -H 'Cookie: JSESSIONID=FFF03011504BAD9F042BEBF4435E1CBD; SESSION=NjYxNzlhZjktZjViNi00NDE3LTgzMzAtNWQyZDQ0NGQwNzlm' \ -d $'{ "title": "标题", "price": 18.88 }' 复制代码
- 文件上传(带参数)
#[derive(Debug, Serialize, Deserialize, Extractible)] struct FileName { // 同时从请求体中解析出简单类型字段值 #[extract(source(from = "body"))] name: String, } // "/upload/<id>" #[handler] async fn upload(file_name: FileName, req: &mut Request, res: &mut Response) { let id = req.param::<String>("id").unwrap(); // 从请求体中取出文件 let file = req.file("file").await; if let Some(file) = file { // 写入目标路径 let dest_file = format!("/tmp/{}", &file.name().unwrap()); if let Ok(x) = std::fs::copy(&file.path(), Path::new(&dest_file)) { // 返回响应 res.render(format!("id:{} \nfile_name:{} \n文件上传成功:{}", id, file_name.name, &dest_file)); } else { // 写入文件失败 GlobalError::new(500, "file store failure", "file store failure").write(res); } } else { // 没有取到文件,返回失败 GlobalError::bad_request("file not found in request", "file not found in request").write(res); } } 复制代码
- Router编写方式:
Router::with_path("/upload/<id>").post(upload) 复制代码
- 请求方式:
curl -X "POST" "http://127.0.0.1:7878/upload/123456" \ -H 'Content-Type: multipart/form-data; charset=utf-8; boundary=__X_PAW_BOUNDARY__' \ -H 'Cookie: JSESSIONID=FFF03011504BAD9F042BEBF4435E1CBD; SESSION=NjYxNzlhZjktZjViNi00NDE3LTgzMzAtNWQyZDQ0NGQwNzlm' \ -F "file=" \ -F "name=hello" 复制代码
结束
到此,基本上大多数使用场景已经囊括进来了,小伙伴们可以根据以上这几个示例编写自己的业务代码。如果还有其他更复杂的应用场景,请参考salvo官方文档