内容介绍
本专题将带你使用逐步实现一个非常常见的功能:在用户注册时,通过发送验证码。RabbitMQ 消息队列
RabbitMQ 是目前市场上最流行的消息队列之一,本章将讨论如何安装部署 RabbitMQ。通过 lapin 集成 RabbitMQ
`lapin` 是一个用 rust 实现的 AMQP 客户端,它可以实现与 RabbitMQ 的交互。通过 lettre 发送邮件
本章将讨论使用 `lettre` 在 rust 中实现发送邮件。我们将分别使用 Gmail 和 Mail.ee 来作测试。实现用户注册与激活
本章将实现最终的功能:用户注册,并发送激活邮件。
实现用户注册与激活
本章将实现最终的功能:用户注册,并发送激活邮件。
handler
我们增加几个 handler,其它都过于简单这里不再赘述。重点来看一下注册时的 handler:
// src/handler.rs
pub async fn register(
Extension(state): Extension<Arc<AppState>>,
Form(frm): Form<form::RegisterForm>,
) -> Result<(StatusCode, HeaderMap, ())> {
let cfg = &state.cfg;
let active_code = model::user::ActiveCode {
code: gen_active_code(&frm.email),
email: frm.email,
email_cfg: cfg.email.clone(),
};
let payload = serde_json::to_string(&active_code).map_err(Error::from)?;
// 发送消息
topic::send(
&cfg.rabbitmq.dsn,
&cfg.rabbitmq.exchange_name,
&cfg.rabbitmq.queue_name,
&cfg.rabbitmq.routing_key,
&payload,
)
.await
.map_err(Error::from)?;
redirect("/active")
}
- 我们将
model::user::ActiveCode
序列化为 JSON 字符串,然后发送到 RabbitMQ 中。你或许有疑问。为什么这个结构体中要包含邮箱配置项(email_cfg
字段)?那是因为在 lapin 的消费者回调中,无法操作外部变量,所以我们需要把那些业务上所需的一些数据全部通过消息队列发送。
消息消费者(发送邮件验证码)
// src/main.rs
#[tokio::main]
async fn main() {
// ...
tokio::spawn(send_active_code(cfg.clone()));
// ...
}
async fn send_active_code(cfg: Config) {
topic::receive(
&cfg.rabbitmq.dsn,
&cfg.rabbitmq.exchange_name,
&cfg.rabbitmq.queue_name,
&cfg.rabbitmq.routing_key,
"MAIL",
move |delivery: DeliveryResult| async move {
tracing::debug!("aaa");
let delivery = match delivery {
Ok(Some(delivery)) => delivery,
Ok(None) => {
tracing::error!("None ");
return;
}
Err(err) => {
tracing::error!("Failed to consume queue message {}", err);
return;
}
};
let message = String::from_utf8_lossy(&delivery.data);
tracing::info!("Received a message: {}", message);
let ac: model::user::ActiveCode = serde_json::from_str(&message).unwrap();
let from = ac.email_cfg.username.clone();
let resp = email::send(
ac.email_cfg,
model::email::Email {
from,
to: ac.email,
subject: format!("激活账号"),
body: format!("你的激活码是:{}", ac.code),
},
)
.await
.unwrap();
tracing::info!("Send email: {:?}", resp);
delivery.ack(BasicAckOptions::default()).await.unwrap();
},
)
.await
.unwrap();
}
在 main()
函数中,我们使用 tokio::spawn(send_active_code(cfg.clone()));
让消息的消费者在一个新的异步任何中执行
而在 send_active_code()
函数的消费者回调中
-
let message = String::from_utf8_lossy(&delivery.data)
:获取消息数据,并转换成字符串 -
let ac: model::user::ActiveCode = serde_json::from_str(&message).unwrap()
:将消息数据反序列化为model::user::ActiveCode
-
最后就是发送邮件
let resp = email::send( ac.email_cfg, model::email::Email { from, to: ac.email, subject: format!("激活账号"), body: format!("你的激活码是:{}", ac.code), }, ) .await .unwrap();
-
进入你填写的邮箱,你应该能收到如图所示的邮件:
let message = String::from_utf8_lossy(&delivery.data)
:获取消息数据,并转换成字符串
let ac: model::user::ActiveCode = serde_json::from_str(&message).unwrap()
:将消息数据反序列化为 model::user::ActiveCode
最后就是发送邮件
进入你填写的邮箱,你应该能收到如图所示的邮件: