惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
Recent Announcements
Recent Announcements
L
LangChain Blog
B
Blog
阮一峰的网络日志
阮一峰的网络日志
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
M
MIT News - Artificial intelligence
D
Docker
WordPress大学
WordPress大学
J
Java Code Geeks
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The GitHub Blog
The GitHub Blog
博客园 - 叶小钗
Last Week in AI
Last Week in AI
Stack Overflow Blog
Stack Overflow Blog
有赞技术团队
有赞技术团队
MyScale Blog
MyScale Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
MongoDB | Blog
MongoDB | Blog
博客园 - Franky

又耳笔记

用AI挣钱之AI建站:二维码生成器工具 用AI挣钱之AI建站:https://markdowntopdf.top Cloudflare Workers实战番外一:用Static Assets托管网站,告别传统方案 Cloudflare Workers实战(五):不止JavaScript,拥抱Python与Rust Cloudflare Workers实战(四):托管和分发静态文件 Cloudflare Workers实战(三):实现认证、重定向与缓存 Cloudflare Workers实战(二):动态修改后端响应 Cloudflare Workers实战(一):随心所欲操作客户端请求 Cloudflare workers不完全指南 使用n8n创作短篇小说 水果风波:信任的代价 用Python将PDF文件转换成图片 rust网络框架Pingora源码阅读3 rust网络框架Pingora源码阅读2 rust网络框架Pingora源码阅读1 Pingora快速入门教程1之总览 Rust模板引擎askama快速入门引擎 使用Loco快速搭建自己的后台系统 用Rust发一封图文并茂的邮件 Rust小项目: 写一个简单的恶意流量阻断器 Rust小项目: 写一个简单的网页爬虫 Rust命令行库Clap快速入门教程 Rust小项目:用Rust写一个端口扫描器 Rust真全栈开发快速入门 rust声明宏快速入门教程 Rust文本处理快速入门教程 RUST web框架axum快速入门教程6之测试 白嫖免费的Rust在线运行时shuttle 用Rust来做以太坊开发5之事件日志及签名 《英语语法分解大全》读后感
RUST web框架axum快速入门教程5之中间件
About 又耳宁 关于技术与股票的一些零碎想法 · 2023-12-23 · via 又耳笔记

本文主要讨论axum的中间件,这也是axum与其他rust web框架极大的不同点,其他框架都定义了自己的接口,而axum直接使用towerServvicelayer的概念, 而tower已经存在一大堆通用的中间件了,所以axum也就自带了一大堆开箱即用的中间件。

往期文章:

本节的Cargo.toml文件依赖如下

[dependencies]
axum = { version="0.6.20", features=["default", "headers"] }
axum-extra = { version = "0.8" }
tokio = { version = "1.0", features = ["full"] }
reqwest = { version="0.11.22", features=["json", "multipart"]}
serde = { version = "1.0", features = ["derive"] }
tower = { version = "0.4", features = ["util"] }
tower-http = { version = "0.4.0", features = ["full"] }
serde_json = "1.0.107"
askama = "0.12"
sqlx = { version = "0.7", features = [ "runtime-tokio", "postgres"] }
matchit = "0.7.3"
rand = "0.8.5"
http = "1.0.0"
hyper = "0.14.27"

快速入门

// https://youerning.top/post/axum/quickstart-5
use std::time::Duration;
use axum::http::HeaderName;
use axum::{
    body::Body,
    routing::get,
    Router,
    http::Request,
};
use tokio::time::sleep;
use tower_http::trace::TraceLayer;
use tower_http::compression::CompressionLayer;
use tower_http::timeout::TimeoutLayer;
use tower_http::cors::{CorsLayer, Any};
use tower_http::request_id::{MakeRequestUuid, SetRequestIdLayer};
use tower::ServiceBuilder;



#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/", get(index_handler))
        .layer(
            // 官方推荐在ServiceBuilder上一次性载入
            ServiceBuilder::new()
                .layer(TraceLayer::new_for_http())
                .layer(CompressionLayer::new())
            	// 超时时间是200ms
                .layer(TimeoutLayer::new(Duration::new(0, 200000)))
            	// 需要设置一个请求头的键名,一般叫x-request-id
                .layer(SetRequestIdLayer::new(HeaderName::from_static("x-request-id"), MakeRequestUuid))
                // 默认情况下不放行,所以需要根据自己需求设置必要的允许规则。
               .layer(CorsLayer::new().allow_methods(axum::http::Method::GET).allow_origin(Any))
                
        );

    let addr = "0.0.0.0:8080";
    axum::Server::bind(&addr.parse().unwrap())
      .serve(app.into_make_service())
      .await
      .unwrap();
}

async fn index_handler(req: Request<Body>) -> String {
    if rand::random() {
        sleep(Duration::new(0, 300000)).await;
    }

    if let Some(req_id) = req.headers().get("x-request-id") {
        // CompressionLayer只有当长度大于32时才会压缩
        format!("request[{:?}] {} with method {} ; make the body length longer than 32", req_id ,req.uri(), req.method())
    } else {
        format!("request[none] {} with method {} ; make the body length longer than 32", req.uri(), req.method())
    }
    
}

上面使用了五个比较常用的中间件。

  • TraceLayer trace中间件, 用于追踪各种事件,在不发送给远端的情况的话,跟日志差不多
  • CompressionLayer 压缩中间件,默认情况下,只有内容长度大于32的时候才会进行压缩
  • TimeoutLayer 超时中间件 如果服务端响应超时就返回408状态码
  • SetRequestIdLayer 为服务端设置请求ID,如果还需要为客户端生成对应的请求ID,那么需要PropagateRequestIdLayer
  • CorsLayer 设置CORS请求头,做过前后端分离的项目应该不陌生

除此之外,tower_http还有超级多的中间件可以使用,有兴趣的可以查看: https://docs.rs/tower-http/0.4.3/tower_http/index.html#modules

顺序

tower_http的中间件嵌套其实就像洋葱一层包一层

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 -----+
           |
           v
        responses

小结

这一节主要了解了一下axum或者说tower的一些常见中间件的使用,如果tower的中间件列表没有自己需要的,可以自己写,虽然会写的不会太难,但是对于没有接触过tower的人来说还是有点难以理解,所以作为快速入门,这里就省略了自己写中间件的内容了, 当然了,也是觉得解释towerService概念需要花很多时间,以后有机会在写相关文章吧。

参考链接