gpt4 book ai didi

asynchronous - 始终返回Ok HttpResponse,然后在actix-web处理程序中执行工作

转载 作者:行者123 更新时间:2023-12-03 11:28:59 27 4
gpt4 key购买 nike

我有一个处理程序来初始化密码重置。它总是返回成功的200状态代码,因此攻击者无法使用它来查找数据库中存储了哪些电子邮件地址。问题是,如果数据库中有一封电子邮件,则需要一段时间才能完成请求(阻止用户查找并使用重置 token 发送实际的电子邮件)。如果用户不在数据库中,则请求将很快返回,因此被攻击者会知道该电子邮件不存在。

在后台处理请求时,我将如何立即返回HTTP响应?

pub async fn forgot_password_handler(
email_from_path: web::Path<String>,
pool: web::Data<Pool>,
redis_client: web::Data<redis::Client>,
) -> HttpResponse {
let conn: &PgConnection = &pool.get().unwrap();
let email_address = &email_from_path.into_inner();
// search for user with email address in users table
match users.filter(email.eq(email_address)).first::<User>(conn) {
Ok(user) => {
// some stuff omitted.. this is what happens:
// create random token for user and store a hash of it in redis (it'll expire after some time)
// send email with password reset link and token (not hashed) to client
// then return with
HttpResponse::Ok().finish(),
}
_ => HttpResponse::Ok().finish(),
}
}

最佳答案

您可以使用Actix Arbiter安排异步任务:

use actix::Arbiter;

async fn do_the_database_stuff(
email: String,
pool: web::Data<Pool>,
redis_client: web::Data<redis::Client>)
{
// async database code here
}

pub async fn forgot_password_handler(
email_from_path: web::Path<String>,
pool: web::Data<Pool>,
redis_client: web::Data<redis::Client>,
) -> HttpResponse {

let email = email_from_path.clone();
Arbiter::spawn(async {
do_the_database_stuff(
email,
pool,
redis_client
);
});

HttpResponse::Ok().finish()
}

如果您的数据库代码正在阻塞,则为了避免占用生命周期长的Actix工作线程,您可以改用自己的线程创建一个新的 Arbiter:
fn do_the_database_stuff(email: String) {
// blocking database code here
}

pub async fn forgot_password_handler(email_from_path: String) -> HttpResponse {
let email = email_from_path.clone();
Arbiter::new().exec_fn(move || {
async move {
do_the_database_stuff(email).await;
};
});

HttpResponse::Ok().finish()
}

这可能需要更多的工作,因为 Poolredis::Client不太可能在线程之间安全共享,因此您也必须解决该问题。这就是为什么我没有在示例代码中包括它们。

与使用 Arbiter产生新的 native 线程相比,使用 std::thread更好。如果将两者混合使用,最终可能会意外地包含使工作人员陷入困境的代码。例如,在 std::thread::sleep上下文中使用 async将暂停恰好在同一工作程序上调度的不相关任务,甚至可能对您想要的任务没有任何影响。

最后,您还可以考虑对体系结构进行更改。如果将繁重的数据库任务纳入其自己的微服务中,则可以自动解决此问题。然后,Web处理程序可以仅发送一条消息(Kafka,RabbitMQ,ZMQ,HTTP或您选择的任何内容)并立即返回。这将使您能够独立于Web服务器扩展微服务-如果密码重置服务仅需要一个实例,则10个Web服务器实例不必表示10个数据库连接。

关于asynchronous - 始终返回Ok HttpResponse,然后在actix-web处理程序中执行工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61650471/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com