当前位置: 首页 > news >正文

【从零开始的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&#xff0c;所以加一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 介绍 &#xff1a;string 数据结构是简单的 key-value 类型。虽然 Redis 是用 C 语言写的&#xff0c;但是 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挖掘机] - 窗口函数 - 计算移动平均

介绍: 在窗口函数使用时&#xff0c;计算的是累积到当前行的所有的数据的相关操作。 实际上&#xff0c;还可以指定更加详细的汇总范围。该汇总范围称为 框架 (frame)。 其实这里也可以理解成一个窗口, 这个窗口是我们可以进行设置的. 之前我们介绍的窗口函数是根据partition…...

域名和hostname

最近用git克隆远程仓库时总是超时&#xff0c;报错说是代理的问题&#xff0c;但打开和关闭代理都没能解决问题&#xff0c;后面了解到可以关闭git命令的全局代理&#xff1a; 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 为边界的正方形 核心思想&#xff1a;枚举正方向的右下角坐标&#xff08;i&#xff0c;j&#xff09;&#xff0c;然后你只需要判断四条边的连续一的最小个数即可&#xff0c;这里是边求连续一的个数同时求解结果。 087. 网格图中机器人回家的最小代价 核心…...

css滚动条的使用

前言&#xff1a; css滚动条的使用。 1、使用案例1&#xff1a;背景不要&#xff0c;只展示一个滚动条 如果是默认整体&#xff0c;::就够用了&#xff0c;如果是某个元素&#xff0c;可以 .abc:: ,如果是scss这种的 &:: ::-webkit-scrollbar {width: 6px; } ::-webkit…...

优化Python代理爬虫的应用

当我们在资源受限的环境中使用Python代理爬虫时&#xff0c;我们需要采取一些优化措施&#xff0c;以确保程序的高效性和稳定性。在本文中&#xff0c;我将分享一些关于如何优化Python代理爬虫在资源受限环境下的应用的实用技巧。 首先我们来了解&#xff0c;哪些情况算是资源…...

[C++] STL_vector使用与常用接口的模拟实现

文章目录 1、vector的介绍2、vector的使用2.1 vector的定义2.2 vector迭代器的使用2.3 vector的空间增长问题 3、vector的增删查改3.1 push_back&#xff08;重点&#xff09;3.2 pop_back&#xff08;重点&#xff09;3.3 operator[]&#xff08;重点&#xff09;3.4 insert3.…...

【LeetCode】167. 两数之和 II - 输入有序数组 - 双指针

目录标题 2023-8-23 09:25:08 2023-8-23 09:25:08 自己写的不是常量级的额外空间&#xff0c;但是写出来了&#xff0c;记录一下。 下次写的时候&#xff0c;请用双指针。 &#xff08;其实我想了想一想&#xff0c;双指针就没感觉出来&#xff1a;因为我只想到双指针两个都…...

YOLOV1

YOU ONLY LOOK ONCE...

美团增量数仓建设新进展

摘要&#xff1a;本文整理自美团系统研发工程师汤楚熙&#xff0c;在 Flink Forward Asia 2022 实时湖仓专场的分享。本篇内容主要分为四个部分&#xff1a; 建设背景核心能力设计与优化业务实践未来展望 点击查看原文视频 & 演讲PPT 一、美团增量数仓的建设背景 美团数仓架…...

​LeetCode解法汇总2337. 移动片段得到字符串

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 描述&#xff1a; 给你两个字…...

Fpass与Fstop

在MATLAB中&#xff0c;“Fpass”、“Fstop”、"Apass"和"Astop"是数字滤波器设计中常用的参数。它们用于定义滤波器的频率响应和滤波器的性能。 "Fpass"表示通带频率&#xff0c;指的是滤波器允许通过的频率范围。在数字滤波器设计中&#xff0…...

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与…...

父组件传给子组件的数据是异步的,为什么会导致子组件比父组件先执行?

当父组件传递给子组件的数据是异步获取的时候&#xff0c;可能会导致子组件先执行的问题。这是因为在 Vue 的更新机制中&#xff0c;当组件的模板开始渲染时&#xff0c;会立即触发子组件的创建和挂载过程&#xff0c;而父组件的数据可能还没有完全加载完成。 具体来说&#xf…...

泛型编程 学习笔记

#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; } 它可以不用…...

电脑文件删除了可以找回吗?分享一种简单恢复删除电脑文件办法!

电脑文件删除了可以找回吗&#xff1f;可以。在原理上讲电脑删除的文件是有希望恢复的&#xff0c;因为操作系统在删除文件的时候并会不会立刻将文件彻底删除。当文件被删除的时候&#xff0c;其文件记录被删除&#xff0c;并且被文件占用的磁盘空间被标记为空闲。 这样对于用户…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代&#xff0c;海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构&#xff0c;在处理大规模数据抓取任务时展现出强大的能力。然而&#xff0c;随着业务规模的不断扩大和数据抓取需求的日益复杂&#xff0c;传统…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

Chrome 浏览器前端与客户端双向通信实战

Chrome 前端&#xff08;即页面 JS / Web UI&#xff09;与客户端&#xff08;C 后端&#xff09;的交互机制&#xff0c;是 Chromium 架构中非常核心的一环。下面我将按常见场景&#xff0c;从通道、流程、技术栈几个角度做一套完整的分析&#xff0c;特别适合你这种在分析和改…...

nnUNet V2修改网络——暴力替换网络为UNet++

更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...

yaml读取写入常见错误 (‘cannot represent an object‘, 117)

错误一&#xff1a;yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因&#xff0c;后面把yaml.safe_dump直接替换成yaml.dump&#xff0c;确实能保存&#xff0c;但出现乱码&#xff1a; 放弃yaml.dump&#xff0c;又切…...