【从零开始的rust web开发之路 二】axum中间件和共享状态使用
系列文章目录
第一章 axum学习使用
第二章 axum中间件使用
文章目录
- 系列文章目录
- 前言
- 一、中间件是什么
- 二、中间件使用
- 常用中间件
- 使用中间件
- 使用TraceLayer中间件实现请求日志打印
- 自定义中间件
- 共享状态
前言
上篇文件讲了路由和参数相应相关的。axum还有个关键的地方是中间件的使用,这篇文件就来说说。
一、中间件是什么
这个概念跟gin框架的中间件概念一样,类似于springboot项目当中的请求过滤器,在请求过来的时候链式执行一些操作。例如鉴权,日志收集,接口幂等等
二、中间件使用
常用中间件
看看官方提供的中间件
TraceLayer用于高级跟踪/日志记录的跟踪层。
CorsLayer 用于处理 CORS。
CompressionLayer用于自动压缩的压缩层 反应。
RequestIdLayer 和 PropagateRequestIdLayer 设置和传播请求 IDS。
CompressionLayer超时的超时层。注意这一点 需要使用 HandleErrorLayer 将超时转换为响应。
我只看了前两个,这里只拿前两个举例。
使用中间件
使用中间件有两种方法,
一种是通过调用route的layer方法
use axum::{routing::get, Router};async fn handler() {}let app = Router::new().route("/", get(handler)).layer(layer_one).layer(layer_two).layer(layer_three);
这样使用顺序结构如下图
requests|v
+----- layer_three -----+
| +---- layer_two ----+ |
| | +-- layer_one --+ | |
| | | | | |
| | | handler | | |
| | | | | |
| | +-- layer_one --+ | |
| +---- layer_two ----+ |
+----- layer_three -----+|vresponses
请求将按照上图顺序执行,每一个都可以提前返回。比如在layer_three进行鉴权操作,没有权限直接就返回,不在调用下一层
还有一种方法是使用tower::ServiceBuilder构建器,例如
use tower::ServiceBuilder;
use axum::{routing::get, Router};async fn handler() {}let app = Router::new().route("/", get(handler)).layer(ServiceBuilder::new().layer(layer_one).layer(layer_two).layer(layer_three),);
遇上一种方法不同的是执行顺序,这种方式执行顺序是
layer_one 、layer_two 、layer_three、 handler、 layer_three、 layer_two、 layer_one
这种方式更符合方法调用直觉,更容易理解
使用TraceLayer中间件实现请求日志打印
首先需要额外引入一些库
tower = { version = "0.4.13" }
tower-http = { version = "0.4.3", features = ["trace"] }
tracing = "0.1.37"
tracing-subscriber = {version = "0.3.17", features = ["env-filter","time","local-time",
]}
然后
//设置日志级别并格式化时间use tracing_subscriber::{fmt::time::OffsetTime};let local_time = OffsetTime::new(UtcOffset::from_hms(8, 0, 0).unwrap(),format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond digits:3]"),);let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("debug")).add_directive("hyper::proto=off".parse().unwrap());// 输出到控制台中let formatting_layer = fmt::layer().with_timer(local_time).with_writer(std::io::stderr);Registry::default().with(env_filter).with(formatting_layer).init();
///设置async fn handler() {}let app = Router::new().route("/", get(handler)).layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()) ///使用日志中间件);
访问服务这时候就能看到请求日志了

自定义中间件
想要自定义中间件,这里介绍两种axum原生的方法
一种是axum::middleware::from_fn
举个例子
use axum::{Router,http::{self, Request},routing::get,response::Response,middleware::{self, Next},
};
///自定义中间件方法
async fn my_middleware<B>(request: Request<B>,next: Next<B>,
) -> Response {// 对请求做一些处理//......//调用下一个中间价let response = next.run(request).await;//......// 对响应做一些处理,返回响应response
}//这里使用中间件
let app = Router::new().route("/", get(|| async { /* ... */ })).layer(middleware::from_fn(my_middleware));
还有一种方法是axum::middleware::from_extractor
举个例子
use axum::{extract::FromRequestParts,middleware::from_extractor,routing::{get, post},Router,http::{header, StatusCode, request::Parts},
};
use async_trait::async_trait;// 执行认证中间件
struct RequireAuth;#[async_trait]
impl<S> FromRequestParts<S> for RequireAuth
whereS: Send + Sync,
{type Rejection = StatusCode;async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {let auth_header = parts.headers.get(header::AUTHORIZATION).and_then(|value| value.to_str().ok());match auth_header {Some(auth_header) if token_is_valid(auth_header) => {Ok(Self)}_ => Err(StatusCode::UNAUTHORIZED),}}
}fn token_is_valid(token: &str) -> bool {// token校验
}async fn handler() {// 认证之后处理
}async fn other_handler() {// 认证之后处理
}let app = Router::new().route("/", get(handler)).route("/foo", post(other_handler))//给上面路由设置认证中间件.route_layer(from_extractor::<RequireAuth>());
类似于这个就是认证中间件的简单模板
共享状态
共享状态是用于多个请求共同访问的一些数据状态。例如db连接,redis连接等等。多个请求任务共享的数据
一共有三种方式
第一种是通过状态提取,举个例子
use axum::{extract::State,routing::get,Router,
};
use std::sync::Arc;struct AppState {// ...
}let shared_state = Arc::new(AppState { /* ... */ });let app = Router::new().route("/", get(handler)).with_state(shared_state);async fn handler(State(state): State<Arc<AppState>>,
) {// ...
}
第二种通过扩展提取
use axum::{extract::Extension,routing::get,Router,
};
use std::sync::Arc;struct AppState {// ...
}let shared_state = Arc::new(AppState { /* ... */ });let app = Router::new().route("/", get(handler)).layer(Extension(shared_state));async fn handler(Extension(state): Extension<Arc<AppState>>,
) {// ...
}
第三种通过闭包去获取
use axum::{Json,extract::{Extension, Path},routing::{get, post},Router,
};
use std::sync::Arc;
use serde::Deserialize;struct AppState {// ...
}let shared_state = Arc::new(AppState { /* ... */ });let app = Router::new().route("/users",post({let shared_state = Arc::clone(&shared_state);move |body| create_user(body, shared_state)}),).route("/users/:id",get({let shared_state = Arc::clone(&shared_state);move |path| get_user(path, shared_state)}),);async fn get_user(Path(user_id): Path<String>, state: Arc<AppState>) {// ...
}async fn create_user(Json(payload): Json<CreateUserPayload>, state: Arc<AppState>) {// ...
}#[derive(Deserialize)]
struct CreateUserPayload {// ...
}
这种方式写起来比较长,但是比较直观
第二篇先说到这儿。等后续说完orm框架时候再结合说一下
相关文章:
【从零开始的rust web开发之路 二】axum中间件和共享状态使用
系列文章目录 第一章 axum学习使用 第二章 axum中间件使用 文章目录 系列文章目录前言一、中间件是什么二、中间件使用常用中间件使用中间件使用TraceLayer中间件实现请求日志打印自定义中间件 共享状态 前言 上篇文件讲了路由和参数相应相关的。axum还有个关键的地方是中间件…...
Vue操作时间
一、获取现在时间 const currentTime () > {let date new Date();let year date.getFullYear(); //月份从0~11,所以加一let month date.getMonth();let dateArr [date.getMonth() 1,date.getDate(),date.getHours(),date.getMinutes(),date.getSeconds(),…...
数据库——Redis 常见数据结构以及使用场景分析
文章目录 1. string2. list3. hash4. set5. sorted set 你可以自己本机安装 redis 或者通过 redis 官网提供的在线 redis 环境。 1. string 介绍 :string 数据结构是简单的 key-value 类型。虽然 Redis 是用 C 语言写的,但是 Redis 并没有使用 C 的字符串…...
数学建模-规划工具箱yalmip
官网下载 实例 %% yalmip 求解 yalmip clc;clear;close all; %% %sdpvar实型变量 intvar 整形变量 binvar 0-1型变量 psdpvar(3,1); %定义变量 %目标函数 要把求最大值转化为最小值 Objective-p(1)^2p(2)^2-p(2)*p(3);%约束条件 Constraints[0<p<1,(p(1)^2p…...
[SQL挖掘机] - 窗口函数 - 计算移动平均
介绍: 在窗口函数使用时,计算的是累积到当前行的所有的数据的相关操作。 实际上,还可以指定更加详细的汇总范围。该汇总范围称为 框架 (frame)。 其实这里也可以理解成一个窗口, 这个窗口是我们可以进行设置的. 之前我们介绍的窗口函数是根据partition…...
域名和hostname
最近用git克隆远程仓库时总是超时,报错说是代理的问题,但打开和关闭代理都没能解决问题,后面了解到可以关闭git命令的全局代理: git config --global --unset http.proxy git config --global --unset https.proxy如果下次要用的…...
echarts 甘特图一组显示多组数据
<template><el-button type"primary" click"addlin">添加线</el-button><el-button type"success" click"addArea">添加区域</el-button><div ref"echart" id"echart" class&qu…...
1139. 最大的以 1 为边界的正方形;2087. 网格图中机器人回家的最小代价;1145. 二叉树着色游戏
1139. 最大的以 1 为边界的正方形 核心思想:枚举正方向的右下角坐标(i,j),然后你只需要判断四条边的连续一的最小个数即可,这里是边求连续一的个数同时求解结果。 087. 网格图中机器人回家的最小代价 核心…...
css滚动条的使用
前言: css滚动条的使用。 1、使用案例1:背景不要,只展示一个滚动条 如果是默认整体,::就够用了,如果是某个元素,可以 .abc:: ,如果是scss这种的 &:: ::-webkit-scrollbar {width: 6px; } ::-webkit…...
优化Python代理爬虫的应用
当我们在资源受限的环境中使用Python代理爬虫时,我们需要采取一些优化措施,以确保程序的高效性和稳定性。在本文中,我将分享一些关于如何优化Python代理爬虫在资源受限环境下的应用的实用技巧。 首先我们来了解,哪些情况算是资源…...
[C++] STL_vector使用与常用接口的模拟实现
文章目录 1、vector的介绍2、vector的使用2.1 vector的定义2.2 vector迭代器的使用2.3 vector的空间增长问题 3、vector的增删查改3.1 push_back(重点)3.2 pop_back(重点)3.3 operator[](重点)3.4 insert3.…...
【LeetCode】167. 两数之和 II - 输入有序数组 - 双指针
目录标题 2023-8-23 09:25:08 2023-8-23 09:25:08 自己写的不是常量级的额外空间,但是写出来了,记录一下。 下次写的时候,请用双指针。 (其实我想了想一想,双指针就没感觉出来:因为我只想到双指针两个都…...
YOLOV1
YOU ONLY LOOK ONCE...
美团增量数仓建设新进展
摘要:本文整理自美团系统研发工程师汤楚熙,在 Flink Forward Asia 2022 实时湖仓专场的分享。本篇内容主要分为四个部分: 建设背景核心能力设计与优化业务实践未来展望 点击查看原文视频 & 演讲PPT 一、美团增量数仓的建设背景 美团数仓架…...
LeetCode解法汇总2337. 移动片段得到字符串
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 描述: 给你两个字…...
Fpass与Fstop
在MATLAB中,“Fpass”、“Fstop”、"Apass"和"Astop"是数字滤波器设计中常用的参数。它们用于定义滤波器的频率响应和滤波器的性能。 "Fpass"表示通带频率,指的是滤波器允许通过的频率范围。在数字滤波器设计中࿰…...
Java快速入门体验
Java快速入门体验 一、环境信息1.1 硬件信息1.2 软件信息 二、Maven安装2.1 Maven介绍2.2 Maven安装包下载2.3 Maven安装2.4 Maven初始化 三、Java安装3.1 JDK下载3.2 JDK安装3.3 JDK初始化 四、开发环境搭建4.1 安装开发工具4.2 关联Maven环境4.2.1 新建JAVA项目4.2.2 Maven与…...
父组件传给子组件的数据是异步的,为什么会导致子组件比父组件先执行?
当父组件传递给子组件的数据是异步获取的时候,可能会导致子组件先执行的问题。这是因为在 Vue 的更新机制中,当组件的模板开始渲染时,会立即触发子组件的创建和挂载过程,而父组件的数据可能还没有完全加载完成。 具体来说…...
泛型编程 学习笔记
#include "iostream"using namespace std;template<typename T> void Print(T a) {cout << a << endl; }int main() {int a 5;double b 2.3;char c e;string d "sdfasd";Print(a);Print(b);Print(c);Print(d);return 0; } 它可以不用…...
电脑文件删除了可以找回吗?分享一种简单恢复删除电脑文件办法!
电脑文件删除了可以找回吗?可以。在原理上讲电脑删除的文件是有希望恢复的,因为操作系统在删除文件的时候并会不会立刻将文件彻底删除。当文件被删除的时候,其文件记录被删除,并且被文件占用的磁盘空间被标记为空闲。 这样对于用户…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
