想注册一个做网站的公司好,网站备案需要年检吗,北京设计公司网站,微商怎么开通系列文章目录
第一章 axum学习使用 文章目录 系列文章目录前言老规矩先看官方文档介绍高级功能兼容性 二、hello world三、路由四#xff0c;handler和提取器五#xff0c;响应 前言
本职java开发#xff0c;兼架构设计。空闲时间学习了rust#xff0c;目前还不熟练掌握。…系列文章目录
第一章 axum学习使用 文章目录 系列文章目录前言老规矩先看官方文档介绍高级功能兼容性 二、hello world三、路由四handler和提取器五响应 前言
本职java开发兼架构设计。空闲时间学习了rust目前还不熟练掌握。想着用urst开发个web服务正好熟悉一下rust语言开发。 目前rust 语言web开发相关的框架已经有很多但还是和javago语言比不了。 这个系列想完整走一遍web开发后续有时间就出orm还有一些别的web用到的库教程。 言归正传开始学习axum框架
老规矩先看官方文档介绍
Axum是一个专注于人体工程学和模块化的Web应用程序框架。
高级功能
使用无宏 API 将请求路由到处理程序。 使用提取程序以声明方式分析请求。 简单且可预测的错误处理模型。 使用最少的样板生成响应。 充分利用塔和塔-http生态系统 中间件、服务和实用程序。 特别是最后一点是与其他框架的区别。 没有自己的中间件系统而是使用towerService。这意味着获得超时、跟踪、压缩、 授权等等免费。它还使您能够与 使用 hyper 或 tonic 编写的应用程序。axumaxumaxum
兼容性
Axum旨在与Tokio和Hyper配合使用。运行时和 传输层独立性不是目标至少目前是这样。
tokio框架在rust异步当中相当流行。axum能很好地搭配tokio实现异步web
二、hello world
看看官方例子
use axum::{routing::get,Router,
};#[tokio::main]
async fn main() {// 构建routerlet app Router::new().route(/, get(|| async { Hello, World! }));// 运行hyper http服务 localhost:3000axum::Server::bind(0.0.0.0:3000.parse().unwrap()).serve(app.into_make_service()).await.unwrap();
}要想使用还需要引入库
[dependencies]
axum 0.6.19
tokio { version 1.29.1, features [full] }
tower 0.4.13这时候就可以运行了访问localhost:3000此时就能在页面看到Hello, World!
三、路由
路由设置路径有哪些handler去处理 handler可以理解为springboot开发当中的controller里面的方法
use axum::{Router, routing::get};// our router
let app Router::new().route(/, get(root)) //路径对应handler.route(/foo, get(get_foo).post(post_foo)).route(/foo/bar, get(foo_bar));// 一个个handler
async fn root() {}
async fn get_foo() {}
async fn post_foo() {}
async fn foo_bar() {}创建路由
Router::new()说一些常用方法 nest方法可以嵌套一些别的路由
use axum::{routing::{get, post},Router,
};
let user_routes Router::new().route(/:id, get(|| async {}));
let team_routes Router::new().route(/, post(|| async {}));let api_routes Router::new().nest(/users, user_routes).nest(/teams, team_routes);let app Router::new().nest(/api, api_routes);
//此时有两个路径
// - GET /api/users/:id
// - POST /api/teams其实就大致相当于springboot当中在controller类上设置总路径。 merge方法将两个路由器合并为一个
use axum::{routing::get,Router,
};// user路由
let user_routes Router::new().route(/users, get(users_list)).route(/users/:id, get(users_show));
// team路由
let team_routes Router::new().route(/teams, get(teams_list));// 合并
let app Router::new().merge(user_routes).merge(team_routes);// 此时接受请求
// - GET /users
// - GET /users/:id
// - GET /teamsrouter可以接受多个handler方法对于不同的请求方式
use axum::{Router, routing::{get, delete}, extract::Path};
let app Router::new().route(/,get(get_root).post(post_root).delete(delete_root),
);
async fn get_root() {}
async fn post_root() {}
async fn delete_root() {}如果你之前用过go语言中的gin框架那么上手这个会简单很多
四handler和提取器
handler是一个异步函数它接受零个或多个“提取器”作为参数并返回一些 可以转换为响应。 处理程序是应用程序逻辑所在的位置也是构建 axum 应用程序的位置 通过在处理程序之间路由。 它采用任意数量的 “提取器”作为参数。提取器是实现 FromRequest 或 FromRequestPart 的类型
例如Json 提取器它使用请求正文和 将其反序列化为 JSON 为某种目标类型可以用来解析json格式
use axum::{extract::Json,routing::post,handler::Handler,Router,
};
use serde::Deserialize;
#[derive(Deserialize)]
struct CreateUser {email: String,password: String,
}
async fn create_user(Json(payload): JsonCreateUser) {// 这里payload参数类型为CreateUser结构体并且字段参数已经被赋值
}
let app Router::new().route(/users, post(create_user));注意需要引入serde 依赖
serde { version 1.0.176, features [derive] }
serde_json 1.0.104还有一些其他的常用的提取器用于解析不同类型参数
use axum::{extract::{Json, TypedHeader, Path, Extension, Query},routing::post,headers::UserAgent,http::{Request, header::HeaderMap},body::{Bytes, Body},Router,
};
use serde_json::Value;
use std::collections::HashMap;// Path用于解析路径上的参数比如/path/:user_id这时候请求路径/path/100那么user_id的值就是100类似springboot当中PathVariable注解
async fn path(Path(user_id): Pathu32) {}// 查询路径请求参数值这里转换成hashmap对象了类似springboot当中RequestParam注解
async fn query(Query(params): QueryHashMapString, String) {}// HeaderMap可以获取所有请求头的值
async fn headers(headers: HeaderMap) {}//TypedHeader可以用于提取单个标头header请注意这需要您启用了axum的headers功能
async fn user_agent(TypedHeader(user_agent): TypedHeaderUserAgent) {}//获得请求体中的数据按utf-8编码
async fn string(body: String) {}//获得请求体中的数据字节类型
async fn bytes(body: Bytes) {}//这个使json类型转换成结构体上面的例子讲了
async fn json(Json(payload): JsonValue) {}// 这里可以获取Request可以自己去实现更多功能
async fn request(request: RequestBody) {}//Extension从请求扩展中提取数据。这里可以获得共享状态
async fn extension(Extension(state): ExtensionState) {}//程序的共享状态需要实现Clone
#[derive(Clone)]
struct State { /* ... */ }let app Router::new().route(/path/:user_id, post(path)).route(/query, post(query)).route(/user_agent, post(user_agent)).route(/headers, post(headers)).route(/string, post(string)).route(/bytes, post(bytes)).route(/json, post(json)).route(/request, post(request)).route(/extension, post(extension));每个handler参数可以使用多个提取器提取参数
use axum::{extract::{Path, Query},routing::get,Router,
};
use uuid::Uuid;
use serde::Deserialize;let app Router::new().route(/users/:id/things, get(get_user_things));#[derive(Deserialize)]
struct Pagination {page: usize,per_page: usize,
}impl Default for Pagination {fn default() - Self {Self { page: 1, per_page: 30 }}
}async fn get_user_things(Path(user_id): PathUuid,pagination: OptionQueryPagination,
) {let Query(pagination) pagination.unwrap_or_default();// ...
}提取器的顺序 提取程序始终按函数参数的顺序运行从左到右。 请求正文是只能使用一次的异步流。 因此只能有一个使用请求正文的提取程序 例如 use axum::Json;
use serde::Deserialize;#[derive(Deserialize)]
struct Payload {}async fn handler(// 这种是不被允许的body被处理了两次string_body: String,json_body: JsonPayload,
) {// ...
}那么如果参数是可选的需要这么多使用Option包裹
use axum::{extract::Json,routing::post,Router,
};
use serde_json::Value;async fn create_user(payload: OptionJsonValue) {if let Some(payload) payload {} else {}
}let app Router::new().route(/users, post(create_user));五响应
响应内容只要是实现 IntoResponse就能返回
use axum::{Json,response::{Html, IntoResponse},http::{StatusCode, Uri, header::{self, HeaderMap, HeaderName}},
};// 空的
async fn empty() {}// 返回string此时text/plain; charsetutf-8 content-type
async fn plain_text(uri: Uri) - String {format!(Hi from {}, uri.path())
}// 返回bytesapplication/octet-stream content-type
async fn bytes() - Vecu8 {vec![1, 2, 3, 4]
}// 返回json格式
async fn json() - JsonVecString {Json(vec![foo.to_owned(), bar.to_owned()])
}// 返回html网页格式text/html content-type
async fn html() - Htmlstatic str {Html(pHello, World!/p)
}// 返回响应码返回值空
async fn status() - StatusCode {StatusCode::NOT_FOUND
}// 返回值的响应头
async fn headers() - HeaderMap {let mut headers HeaderMap::new();headers.insert(header::SERVER, axum.parse().unwrap());headers
}// 数组元组设置响应头
async fn array_headers() - [(HeaderName, static str); 2] {[(header::SERVER, axum),(header::CONTENT_TYPE, text/plain)]
}// 只要是实现IntoResponse 都可以返回
async fn impl_trait() - impl IntoResponse {[(header::SERVER, axum),(header::CONTENT_TYPE, text/plain)]
}关于自定义IntoResponse看看ai怎么说
要自定义实现IntoResponse按照以下步骤进行 创建一个实现http::Response的结构体该结构体将承载您的自定义响应对象。 创建一个impl块实现IntoResponse trait。 在into_response方法中根据需要生成您的自定义响应。
use axum::{http::{Response, StatusCode}, into_response::IntoResponse, response::Html};// 创建一个自定义响应对象
struct MyResponse(String);// 创建一个impl块实现IntoResponse trait
impl IntoResponse for MyResponse {type Body HtmlString;type Error std::convert::Infallible;fn into_response(self) - ResponseSelf::Body {// 根据需要生成您的自定义响应Response::builder().status(StatusCode::OK).header(Content-Type, text/html).body(Html(self.0)).unwrap()}
}
在上面的代码中我们实现了一个名为MyResponse的自定义响应对象并为其实现了IntoResponse trait。在into_response方法中我们将自定义响应对象转换为一个HTML响应并返回。
您可以像下面这样使用这个自定义响应对象
async fn my_handler() - impl IntoResponse {MyResponse(h1Hello, Axum!/h1.to_string())
}