文件上传下载先暂告一段落,接下来我们来开发授权服务。我们选用actix-web框架进行开发,其它的框架还有rocket、axum、wrap等,大家可以根据自己的喜好进行选择。只所以选择actix-web,主要发现写法和spring有点像,采用的是分散路由的方式,可以通过宏进行方式进行注解,后来发现还是得进行集中注册,感觉被骗了。言归正传,既选之则用之,先来熟悉下actix-web的用法。
首先创建完工程后,需要在cargo.toml中添加相关的依赖
[dependencies]
actix-web = "4"
actix-multipart="0.4.0"
futures-util="0.3.25"
async-stream="0.3.3"
serde = { version = "1.0", features = ["derive"] }
下面来启动一个web服务器并实现一个基础的服务,访问服务器的时候会返回一个ok,如下:
use actix_web::*;
#[get("/")]
async fn index() -> impl Responder {
HttpResponse::Ok().body("ok")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(||{
App::new().service(index)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
看起来是不是挺简单的,我们通过rust宏来标记一个路由为'/',请求为get方法的服务,是不是看起来和spring的写法很像,可惜美中不足的是还需要把服务手动注册到HttpServer上,即下面的代码:
HttpServer::new(||{
App::new().service(index)
})
其中index就是上面的index方法,可以写多个,如:
App::new().service(method1)
.service(method2)
.service(method3)
熟悉了相关结构,下面再来看下,如何实现相关的表单、queryParam、multipart等参数的接收
use actix_web::{get, post, web, App, HttpServer, Responder, HttpResponse, HttpRequest, FromRequest, HttpMessage};
use actix_web::web::{Form, Bytes, Query, Payload};
use actix_web::dev::{ServiceRequest, AppConfig};
use serde::Deserialize;
use std::collections::HashMap;
use actix_multipart::Multipart;
use futures_util::stream::StreamExt;
// 需要添加serde依赖
#[derive(Deserialize)]
struct TestData {
name: String,
value: String
}
#[get("/")]
async fn index() -> impl Responder {
HttpResponse::Ok().body("ok")
}
#[get("/{name}/{value}")]
async fn url_path_param(urlParams: web::Path<TestData>) -> impl Responder {
let params=urlParams.into_inner();
println!("{},{}",params.name,params.value);
HttpResponse::Ok().body("ok")
}
#[get("/queryParam")]
async fn query_param(param:Query<TestData>) -> impl Responder {
println!("{},{}",param.name,param.value);
HttpResponse::Ok().body("ok")
}
// query param参数也可以通过通过HashMap接收
#[get("/queryParam2")]
async fn query_param2(queryParams:Query<HashMap<String,String>>) -> impl Responder {
let params=queryParams.into_inner();
println!("{:?},{:?}",params.get("name"),params.get("value"));
HttpResponse::Ok().body("ok")
}
#[get("/{name}/{value}/compose")]
async fn compose(urlParams: web::Path<TestData>,queryParams:Query<TestData>) -> impl Responder {
let url_params=urlParams.into_inner();
println!("urlPath:{:?},{:?}",url_params.name,url_params.value);
println!("query:{:?},{:?}",queryParams.name,queryParams.value);
HttpResponse::Ok().body("ok")
}
#[post("/formRequest")]
async fn post_form(req :Form<TestData>) -> impl Responder {
println!("{:?},{}",req.name,req.value);
HttpResponse::Ok().body("ok")
}
#[post("/bodyRequest")]
async fn body_request(mut payload :Payload) -> impl Responder {
let body=payload.next().await.unwrap().unwrap().to_vec();
println!("{:?}",String::from_utf8(body));
HttpResponse::Ok().body("ok")
}
// 需要添加actix-multipart依赖
#[post("/multipartRequest")]
async fn multipart_request(mut multipart:actix_multipart::Multipart) -> impl Responder {
while let Some(item) = multipart.next().await {
let mut field = item.unwrap();
// Field in turn is stream of *Bytes* object
while let Some(chunk) = field.next().await {
println!("-- CHUNK: \n{:?}", std::str::from_utf8(&chunk.unwrap()));
}
};
HttpResponse::Ok().body("ok")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(move || {
App::new()
.service(index)
.service(url_path_param)
.service(query_param)
.service(query_param2)
.service(compose)
.service(post_form)
.service(body_request)
.service(multipart_request)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
相关代码比较简单,就不一一介绍了,重点说两个
1、如果要使用multipart/form-data这种格式,需要单独添加actix-multipart依赖
2、因为涉及到网络传输和对象转换,请求的接收对象需要添加#[derive(Deserialize)]宏
网友评论