你是否也困在redis,知其然不知其所以然~~ 项目中,到底怎么用?? 一个简单的实例,使用消息队列实现下yii异步发送邮件
redis~~准备工作:
首先得配置redis服务,之前写过相关的文章,可以参考下这里 https://segmentfault.com/a/11...
yii的redis操作库:https://github.com/yiisoft/yi...
使用composer安装redis的依赖库
php composer.phar require --prefer-dist yiisoft/yii2-redis
web.php的相关配置:
return [
//....
'components' => [
'redis' => [
'class' => 'yii\redis\Connection',
'hostname' => 'localhost',
'port' => 6379,
'database' => 0,
],
]
];
到此,yii中就可以使用redis进行操作了
redis~~同步与异步
那么如何实现异步消息队列发送邮件呢??
传统的操作方法是这样的:
用户输入邮件信息
服务器获取用户输入的数据,提交到第三方的邮件服务器
第三方邮件服务器发送邮件,返回处理结果
异步的处理邮件发送:
用户输入邮件相关信息
将注册信息存储在内存队列,通知用户发送成功
服务器端监听内存队列,将内存队列中的邮件数据依次发送 用户感知不到
两者的区别在哪?
异步相对于同步来说,页面非阻塞,减少了用户等待的时间体验相对来说比较好
redis~~邮件发送
原理:
用户输入邮件信息,服务器接收到输入的邮件信息,调用mail的过程,实则是对mail类属性赋值的过程,这个时候,我们可以抓取用户的信息,存储到队列,然后在队列中,依次读取邮件信息,进行发送
//实例化mail组件
$mailer = Yii::$app->mailer->compose();
$mailer->setFrom('发件人地址');
$mailer->setTo('收件人地址');
$mailer->setSubject('发送标题');
//if ($mailer->send() && $this->reg($data, 'regbymail')) {
//注意这里 本身是直接调用 send方法 进行发送 现在重写父类方法 使用redis进行处理
if ($mailer->queue()) {
return true;
}
这个时候 会去实例化mail类 进行邮件发送,这个时候 我们可以抓取邮件信息 存储到队列中
<?php
namespace mail\mailerqueue;
use Yii;
class Message extends \yii\swiftmailer\Message
{
/*抓取邮件信息到redis的队列*/
public function queue()
{
$redis = Yii::$app->redis;
if (empty($redis)) {
throw new \yii\base\InvalidConfigException('redis not found in config.');
}
// 0 - 15 select 0 select 1
// db => 1
$mailer = Yii::$app->mailer;
//mail邮件存储的数据库 是否存在
if (empty($mailer) || !$redis->select($mailer->db)) {
throw new \yii\base\InvalidConfigException('db not defined.');
}
//抓取邮件信息
$message = [];
$message['from'] =array_keys($this->from);
$message['to'] = array_keys($this->getTo());
$message['cc'] = array_keys($this->getCc());
$message['bcc'] = array_keys($this->getBcc());
$message['reply_to'] = array_keys($this->getReplyTo());
$message['charset'] = array_keys($this->getCharset());
$message['subject'] = array_keys($this->getSubject());
//获取邮件信息及子信息
$parts = $this->getSwiftMessage()->getChildren();
if (!is_array($parts) || !sizeof($parts)) {
$parts = [$this->getSwiftMessage()];
}
foreach ($parts as $part) {
if (!$part instanceof \Swift_Mime_Attachment) {
//获取内容类型
switch($part->getContentType()) {
case 'text/html':
$message['html_body'] = $part->getBody();
break;
case 'text/plain':
$message['text_body'] = $part->getBody();
break;
}
if (!$message['charset']) {
$message['charset'] = $part->getCharset();
}
}
}
//序列化抓取的内容 存放到队列中
return $redis->rpush($mailer->key, json_encode($message));
}
}
接下来就是读取redis队列,进行发送的过程
<?php
namespace mail\mailerqueue;
use Yii;
class MailerQueue extends \yii\swiftmailer\Mailer
{
public $messageClass = "doctorjason\mailerqueue\Message";
public $key = 'mails';
public $db = '1';
/*发送邮件*/
public function process()
{
$redis = Yii::$app->redis;
if (empty($redis)) {
throw new \yii\base\InvalidConfigException('redis not found in config.');
}
//如果队列中 存在数据
if ($redis->select($this->db) && $messages = $redis->lrange($this->key, 0, -1)) {
$messageObj = new Message;
//遍历邮件列表
foreach ($messages as $message) {
$message = json_decode($message, true);
if (empty($message) || !$this->setMessage($messageObj, $message)) {
throw new \ServerErrorHttpException('message error');
}
if ($messageObj->send()){
$redis->lrem($this->key, -1, json_encode($message));
}
}
}
return true;
}
//设置消息头部
public function setMessage($messageObj, $message)
{
if (empty($messageObj)) {
return false;
}
if (!empty($message['from']) && !empty($message['to'])) {
$messageObj->setFrom($message['from'])->setTo($message['to']);
if (!empty($message['cc'])) {
$messageObj->setCc($message['cc']);
}
if (!empty($message['bcc'])) {
$messageObj->setBcc($message['bcc']);
}
if (!empty($message['reply_to'])) {
$messageObj->setReplyTo($message['reply_to']);
}
if (!empty($message['charset'])) {
$messageObj->setCharset($message['charset']);
}
if (!empty($message['subject'])) {
$messageObj->setSubject($message['subject']);
}
if (!empty($message['html_body'])) {
$messageObj->setHtmlBody($message['html_body']);
}
if (!empty($message['text_body'])) {
$messageObj->setTextBody($message['text_body']);
}
return $messageObj;
}
return false;
}
}
到此 我们就实现了redis队列异步发送邮件
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。