【从零开始的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; } 它可以不用…...
电脑文件删除了可以找回吗?分享一种简单恢复删除电脑文件办法!
电脑文件删除了可以找回吗?可以。在原理上讲电脑删除的文件是有希望恢复的,因为操作系统在删除文件的时候并会不会立刻将文件彻底删除。当文件被删除的时候,其文件记录被删除,并且被文件占用的磁盘空间被标记为空闲。 这样对于用户…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
