首页 > 其他分享 >axum的状态共享

axum的状态共享

时间:2023-11-02 09:55:30浏览次数:40  
标签:状态 axum Clone db pub new 共享

状态共享是指,在整个应用或不同路由之间,共享一份数据。axum 提供了方便的状态共享机制,但可能也会踩坑。本章将带你学习如何在 axum web 应用中共享状态。

如何进行状态共享

axum 使用 Layer 来实现状态共享。

定义路由时,使用 layer() 加入要共享的数据,在需要获取该共享数据的 handler 里,使用 Extension 这个 extract 来获取。

什么样的数据才能进行共享

出于并发原因,只有实现了 Clone trait 的数据类型才能进行共享。

下面模拟一个场景:在所有 handler 里都要获取用户信息。

定义数据结构

#[derive(Clone)]
pub struct UserInfo {
    pub username: String,
}

在路由中添加共享数据

let app = Router::new()
        .route("/user", routing::get(show_user_info))
        .layer(AddExtensionLayer::new(UserInfo {
            username: "axum.rs".to_string(),
        }));

我们通过在路由列表之后,使用 layer() 添加共享数据。注意,共享数据不是直接添加进去的,而是通过 AddExtensionLayer::new() 来实现。

在 handler 中获取共享数据

async fn show_user_info(Extension(info): Extension<UserInfo>) -> String {
    format!("Sigined User: {}", info.username)
}

本部分代码可以在这里找到。

如何让那些“顽固分子”也能进行共享

对于我们自己定义的数据结构来说,可以很明确的实现 Clone,而在实际开发中,你可能需要共享第三方库里的数据结构,而这个数据结构并没有实现 Clone,这时候该怎么办?

答案是使用 std::sync::Arc 这个智能指针。你现在脑海里应该明确两点:

  • axum 共享的数据必须是 Clone 的,也就是说不 move 它的所有权

  • Arc 是“线程安全”的引用计数智能指针,它只会读取值,不会转移所有权

定义数据结构

下面,我们将上例中的数据结构中实现 Clone 的部分删除:

pub struct UserInfo {
    pub username: String,
}

在路由中添加共享数据

let app = Router::new()
        .route("/user", routing::get(show_user_info))
        .layer(AddExtensionLayer::new(Arc::new(UserInfo {
            username: "axum.rs".to_string(),
        })));

在 handler 中获取共享数据

async fn show_user_info(Extension(info): Extension<Arc<UserInfo>>) -> String {
    format!("Sigined User: {}", info.username)
}

本部分代码可以在这里找到。

共享复合数据

日常开发中,要共享状态的往往不只一个结构体。而且,这些要共享的结构体也可能出现有些实现了 Clone,有些没有实现。

解决方案是,将这些共享状态封装到一个结构体中。对于那些没有实现 Clone 的,可以:

  • 在这个封装的结构体中,使用 Arc 进行包装,而这个封装的结构体本身要实现 Clone

  • 使用常规方式封装结构体,并且不实现 Clone。通过 Arc 共享这个封装的结构体

下面以第一种方式来演示。

定义数据结构

#[derive(Clone)]
pub struct DatabaseClient {
    pub dsn: String,
}
pub struct RedisClient {
    pub host: String,
}

#[derive(Clone)]
pub struct AppState {
    pub db: DatabaseClient,
    pub rdb: Arc<RedisClient>,
}

在路由中添加共享数据

let db_client = DatabaseClient {
        dsn: "host=pg.axum.rs port=5432 user=axum_rs password=axum.rs sslmode=disable".to_string(),
    };
    let redis_client = Arc::new(RedisClient {
        host: "redis.axum.rs".to_string(),
    });

    let app = Router::new()
        .route("/status", routing::get(status))
        .layer(AddExtensionLayer::new(AppState {
            db: db_client,
            rdb: redis_client,
        }));

在 handler 中获取共享数据

async fn status(Extension(state): Extension<AppState>) -> String {
    format!(
        "database dsn: {}, redis host: {}",
        state.db.dsn, state.rdb.host
    )
}

本部分代码可以在这里找到。

本章对 axum 中共享状态进行了讨论,相关源代码可以在代码库找到。

思考题

试着自己实现第二种方式,即:

使用常规方式封装结构体,并且不实现 Clone。通过 Arc 共享这个封装的结构体

参考答案:

定义数据结构

#[derive(Clone)]
pub struct DatabaseClient {
    pub dsn: String,
}
pub struct RedisClient {
    pub host: String,
}

pub struct AppState {
    pub db: DatabaseClient,
    pub rdb: RedisClient,
}

在路由中添加共享数据

let db_client = DatabaseClient {
        dsn: "host=pg.axum.rs port=5432 user=axum_rs password=axum.rs sslmode=disable".to_string(),
    };
    let redis_client = RedisClient {
        host: "redis.axum.rs".to_string(),
    };

    let app = Router::new()
        .route("/status", routing::get(status))
        .layer(AddExtensionLayer::new(Arc::new(AppState {
            db: db_client,
            rdb: redis_client,
        })));

在 handler 中获取共享数据

async fn status(Extension(state): Extension<Arc<AppState>>) -> String {
    format!(
        "database dsn: {}, redis host: {}",
        state.db.dsn, state.rdb.host
    )
}

本部分代码可以在这里找到。

标签:状态,axum,Clone,db,pub,new,共享
From: https://www.cnblogs.com/pythonClub/p/17804743.html

相关文章

  • CPU缓存伪共享
    CPU缓存什么东西?当然这个问题很多人有可能觉得比较傻,CPU缓存什么,肯定是缓存数据(代码)啊,要不然还能缓存啥,这个确实没问题,但是CPU到底缓存什么样的数据呢?因为对CPU来说,无论是指令,还是数据,都是数据,他如果要缓存,缓存的单位是啥?要缓存的内容是啥呢?接下来咱们一点点解析这部分的内容,首先......
  • “共享书角”图书借还管理系统 小程序-计算机毕业设计源码+LW文档
    小程序框架:uniapp小程序开发软件:HBuilderX小程序运行软件:微信开发者数据库:DROPTABLEIFEXISTSchujiezhe;/*!40101SET@saved_cs_client=@@character_set_client/;/!40101SETcharacter_set_client=utf8/;CREATETABLEchujiezhe(idbigint(20)NOTNULLAUT......
  • 如何在Vue组件中访问Vuex store中的状态?
    在Vue组件中访问Vuexstore中的状态,可以通过计算属性(computedproperties)或者直接通过$store.state来实现。下面是两种常见的方法:1:使用计算属性(computedproperties):在Vue组件中,定义一个计算属性来获取Vuexstore中的状态。计算属性会根据状态的变化自动更新。exportdefaul......
  • 登录报错后,状态码是401并弹出登录框
    前后端分离的项目,登录失败后会弹出一个非前端页面登录框。这是因为登录失败,返回的响应表头里添加了WWW-Authenticate属性WWW-Authenticate:Basicrealm="oauth2/client"Basic认证失败时,接口返回的httpstatuscode=401时,大部分浏览器收到此响应头,会弹出下图的认证窗口来辅助用户......
  • HTTP 和 HTTPS(请求响应报文格式 + 请求方法 + 响应状态码 + HTTPS 加密流程 + Cookie
    文章目录   1.HTTP是什么   2.HTTP请求报文和响应报文的格式       1)请求报文格式       2)响应报文格式       3)报文中空行的作用   3.HTTP的长连接和短连接   4.URL       1)在浏览器中输入www.baidu.com后执行的全部过......
  • Azkaban Execute Flow一直处于PREPARING状态,不执行
    启动了任务后,任务一直处于Preparing状态,无法执行,详情如下: 原因:内存问题,过滤器会检查executor主机空余内存是否会大于6G,若不足6G,则web-server不会将任务交由该主机执行,需要修改azkabn-web下的azkaban.properties配置文件,去掉MinimumFreeMemory。将配置项:azkab......
  • OpenHarmony 状态变量更改通知:@Watch 装饰器
    @Watch应用于对状态变量的监听。如果开发者需要关注某个状态变量的值是否改变,可以使用@Watch为状态变量设置回调函数。说明:从APIversion9开始,该装饰器支持在ArkTS卡片中使用。概述@Watch用于监听状态变量的变化,当状态变量变化时,@Watch的回调方法将被调用。@Watch......
  • 如何使用saveInstanceState保存活动状态?
    内容来自DOChttps://q.houxu6.top/?s=如何使用saveInstanceState保存活动状态?我已经在AndroidSDK平台上工作了一段时间,但是不太清楚如何保存应用程序的状态。因此,针对这个“Hello,Android”示例进行了一些微小的调整:packagecom.android.hello;importandroid.app.Activ......
  • 软件设计-状态模式
    publicclass状态模式{publicstaticvoidmain(String[]args){Contextcontext=newContext();context.Request();context.Request();context.Request();//System.out.println(context.getState());context......
  • 两台电脑在相同网络下使用共享文件夹进行文件的传递
    如题,如何使用共享文件夹,实现两台电脑的文件传递。首先要保证两台电脑处于同一网络下(同一WIFI下)例如电脑A上有个share_file文件夹,我们的目的是,将其变成两台电脑共享的文件夹。电脑A和B都可以对其进行文件的增删改查。电脑A的操作: 右键点击文件夹,选择属性,出现对话框后点击共......