【从零开始的rust web开发之路 一】axum学习使用

系列文章目录

第一章 axum学习使用

文章目录

  • 系列文章目录
  • 前言
    • 老规矩先看官方文档介绍
    • 高级功能
    • 兼容性
  • 二、hello world
  • 三、路由
  • 四,handler和提取器
  • 五,响应


前言

本职java开发,兼架构设计。空闲时间学习了rust,目前还不熟练掌握。想着用urst开发个web服务,正好熟悉一下rust语言开发。
目前rust 语言web开发相关的框架已经有很多,但还是和java,go语言比不了。
这个系列想完整走一遍web开发,后续有时间就出orm,还有一些别的web用到的库教程。
言归正传,开始学习axum框架

老规矩先看官方文档介绍

Axum是一个专注于人体工程学和模块化的Web应用程序框架。

高级功能

使用无宏 API 将请求路由到处理程序。
使用提取程序以声明方式分析请求。
简单且可预测的错误处理模型。
使用最少的样板生成响应。
充分利用塔和塔-http生态系统 中间件、服务和实用程序。
特别是,最后一点是与其他框架的区别。 没有自己的中间件系统,而是使用tower::Service。这意味着获得超时、跟踪、压缩、 授权等等,免费。它还使您能够与 使用 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 /teams

router可以接受多个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): Json<CreateUser>) {// 这里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): Path<u32>) {}// 查询路径请求参数值,这里转换成hashmap对象了,类似springboot当中@RequestParam注解
async fn query(Query(params): Query<HashMap<String, String>>) {}// `HeaderMap`可以获取所有请求头的值
async fn headers(headers: HeaderMap) {}//TypedHeader可以用于提取单个标头(header),请注意这需要您启用了axum的headers功能
async fn user_agent(TypedHeader(user_agent): TypedHeader<UserAgent>) {}//获得请求体中的数据,按utf-8编码
async fn string(body: String) {}//获得请求体中的数据,字节类型
async fn bytes(body: Bytes) {}//这个使json类型转换成结构体,上面的例子讲了
async fn json(Json(payload): Json<Value>) {}// 这里可以获取Request,可以自己去实现更多功能
async fn request(request: Request<Body>) {}//Extension从"请求扩展"中提取数据。这里可以获得共享状态
async fn extension(Extension(state): Extension<State>) {}//程序的共享状态,需要实现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): Path<Uuid>,pagination: Option<Query<Pagination>>,
) {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: Json<Payload>,
) {// ...
}

那么如果参数是可选的需要这么多,使用Option包裹

use axum::{extract::Json,routing::post,Router,
};
use serde_json::Value;async fn create_user(payload: Option<Json<Value>>) {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; charset=utf-8` content-type
async fn plain_text(uri: Uri) -> String {format!("Hi from {}", uri.path())
}// 返回bytes`application/octet-stream` content-type
async fn bytes() -> Vec<u8> {vec![1, 2, 3, 4]
}// 返回json格式
async fn json() -> Json<Vec<String>> {Json(vec!["foo".to_owned(), "bar".to_owned()])
}// 返回html网页格式`text/html` content-type
async fn html() -> Html<&'static str> {Html("<p>Hello, 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 = Html<String>;type Error = std::convert::Infallible;fn into_response(self) -> Response<Self::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("<h1>Hello, Axum!</h1>".to_string())
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/49458.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

同步、异步无障碍:Python异步装饰器指南

一、引言 Python异步开发已经非常流行了&#xff0c;一些主流的组件像MySQL、Redis、RabbitMQ等都提供了异步的客户端&#xff0c;再处理耗时的时候不会堵塞住主线程&#xff0c;不但可以提高并发能力&#xff0c;也能减少多线程带来的cpu上下文切换以及内存资源消耗。但在业务…

Linux dd命令

Linux中的dd命令是一个强大的块级命令行工具&#xff0c;用于进行数据转换和复制操作。它可以从一个块设备或文件中读取数据&#xff0c;并将数据写入另一个块设备或文件中。dd命令的基本语法如下&#xff1a; dd ifinput_file ofoutput_file [options]以下是dd命令的一些常用…

回归预测 | MATLAB实现SSA-RF麻雀搜索优化算法优化随机森林算法多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现SSA-RF麻雀搜索优化算法优化随机森林算法多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现SSA-RF麻雀搜索优化算法优化随机森林算法多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;…

2023年国赛 高教社杯数学建模思路 - 案例:退火算法

文章目录 1 退火算法原理1.1 物理背景1.2 背后的数学模型 2 退火算法实现2.1 算法流程2.2算法实现 建模资料 ## 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 退火算法原理 1.1 物理背景 在热力学上&a…

组合总和-LeetCode

给你一个无重复元素的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的所有不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序返回这些组合。 candidates 中的同一个数字可以无限制重复被选取 。如果至少一个…

【Python】PyCharm配置外部工具

【摘要】 QT Designer配置 Designer绘制的UI文件转换成py文件 UI用到的图片资源文件转换成py文件 注意&#xff1a;使用豆瓣原安装比较快 pip install * -i http://pypi.douban.com/simple --trusted-host pypi.douban.com 1&#xff0c;File->Settings->Tools->…

手机无人直播软件,有哪些优势?

近年来&#xff0c;随着手机直播的流行和直播带货的市场越来越大&#xff0c;手机无人直播软件成为许多商家开播带货的首选。在这个领域里&#xff0c;声音人无人直播系统以其独特的优势&#xff0c;成为市场上备受瞩目的产品。接下来&#xff0c;我们将探讨手机无人直播软件给…

Office ---- excel ---- 怎么批量设置行高

解决方法&#xff1a; 调整行高即可

C# 流Stream详解(2)——FileStream、BinaryReader、MemorySream、SreamReader等之间的关系

【文件流】 电脑上的文件有很多&#xff0c;文本文件、音频文件、视频文件、图片文件等&#xff0c;这些文件会被持久化存储在磁盘上&#xff0c;其本质都是一堆二进制数据。 FileStream用于读取二进制文件。电脑上的所有文件&#xff0c;不管是文本、音频、视频还是其他任意…

微信小程序教学系列(5)

微信小程序教学系列 第五章&#xff1a;小程序发布与推广 第一节&#xff1a;小程序发布流程介绍 小伙伴们&#xff0c;欢迎来到第五章的教学啦&#xff01;在这一章中&#xff0c;我们将一起来探索小程序的发布与推广流程。你准备好了吗&#xff1f;让我们开始吧&#xff0…

C语言学习系列-->【关于qsort函数的详解以及它的模拟实现】

文章目录 一、概述二、qsort函数参数介绍三、qsort实现排序3.1 qsort实现整型数组排序3.2 qsort实现结构体数组排序 四、模拟实现qsort函数 一、概述 对数组的元素进行排序 对数组中由 指向的元素进行排序&#xff0c;每个元素字节长&#xff0c;使用该函数确定顺序。 此函数使…

mongodb集群

端口192.168.115.3 192.168.115.4 1192.168.115.5 下载MongoDB软件包版本为4.2.14并安装 rpm -ih --force --nodeps *.rpm 2创建文件夹mkdir -p /opt/local/mongo-cluster/conf 3.在目录里创建配置文件cd /opt/local/mongo-cluster/conf …

windows下安装使用git-lfs克隆大文件

下载安装git-lfs工具 首先去git-lfs这里&#xff0c;下载相应平台的工具&#xff0c;我下载的windows版本&#xff0c;非安装版本&#xff0c;直接配置到系统环境变量里 执行以下命令验证是否成功 git lfs install 克隆数据集 这样自动会下载里边的大文件 git clone https:/…

vue项目中使用ts的枚举类型

vue项目中要使用ts的枚举类型需要为script标签的lang属性添加ts属性值 <script lang"ts" setup> </script > 声明枚举类型&#xff1a; //语法 /* enum 枚举名称 {可能的值 }*/ enum scenic_status {"正常" 1,"审核中","暂停…

如何撰写骨灰级博士论文?这是史上最全博士论文指导!

博士论文的写作是博士研究生主要要完成的工作。由于存在着较高的难度&#xff0c;较长的写作周期&#xff0c;以及在创新&#xff0c;写作规范&#xff0c;实际及理论意义等方面有着比较高的要求&#xff0c;博士论文的完成一般说来是有相当难度的。一篇好的博士论文不仅是一本…

2023年中,量子计算产业现状——

2023年上半年&#xff0c;量子计算&#xff08;QC&#xff09;领域取得了一系列重要进展和突破&#xff0c;显示出量子计算技术的快速发展和商业应用的不断拓展。在iCV TAnk近期发表的一篇报告中&#xff0c;团队从制度进步、产业生态、投融资形势、总结与展望四个方面对量子计…

Vue3 中引入液晶数字字体(通常用于大屏设计)

一、下载 .ttf 字体文件到本地&#xff0c;放在 src 中的 assets 文件下 下载液晶字体 DS-Digital.ttf 二、在 css 文件中引入字体 /* src/assets/fonts/dsfont.css */ font-face {font-family: electronicFont;src: url(./DS-Digital.ttf);font-weight: normal;font-styl…

Mybatis 建立依赖失败:报错Dependency ‘mysql:mysql-connector-java:8.0.28‘ not found

Mybatis 建立依赖失败&#xff1a;报错Dependency ‘mysql:mysql-connector-java:8.0.28’ not found 解决办法&#xff1a; 写完依赖代码&#xff0c;直接重构&#xff0c;下载依赖。 图片: ![Alt](https://img-home.csdnimg.cn/images/20220524100510.png Mac 版本注意Ide…

编写Dockerfile制作Web应用系统nginx镜像,生成镜像nginx:v1.1,并推送其到私有仓库

Docker 镜像是一个特殊的文件系统&#xff0c;除了提供容器运行时所需的程序、库、资源、配置等文件外&#xff0c;还包含了一些为运行时准备的一些配置参数&#xff08;如匿名卷、环境变量、用户等&#xff09;。镜像不包含任何动态数据&#xff0c;其内容在构建之后也不会被改…

深度学习论文: WinCLIP: Zero-/Few-Shot Anomaly Classification and Segmentation

深度学习论文: WinCLIP: Zero-/Few-Shot Anomaly Classification and Segmentation WinCLIP: Zero-/Few-Shot Anomaly Classification and Segmentation PDF: https://arxiv.org/pdf/2303.14814.pdf PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: h…