Yii2数据更新后多通知逻辑与页面跳转冲突问题求助
嘿,我来帮你搞定这个问题!你之前遇到的核心问题是用redirect直接跳转到短信API导致后续代码无法执行,而且要支持多组通知的话,得把逻辑梳理得更清晰才行。下面给你两个靠谱的解决方案,从基础到进阶都有:
方案1:优化同步Curl请求(适合通知量小的场景)
首先咱们把短信发送的逻辑封装成一个可复用的方法,这样添加多组通知的时候就不用重复写代码了。而且不管短信发送成功与否,最后统一执行跳转——毕竟跳转是用户预期的核心操作,短信发送的结果可以用日志记录下来方便后续排查。
先在你的控制器里加一个私有方法:
/** * 发送短信通知 * @param array $mobiles 目标手机号数组 * @param string $message 短信内容 * @return bool 发送是否成功 */ private function sendSmsNotification($mobiles, $message) { // 过滤空手机号 + 去重 $mobiles = array_filter(array_unique($mobiles)); if (empty($mobiles)) { Yii::info('No valid mobiles to send SMS', 'sms_notification'); return false; } $mobileStr = implode(",", $mobiles); $curl = new \linslin\yii2\curl\Curl(); // 建议把短信配置移到params.php里,不要硬编码 $params = [ 'sender' => Yii::$app->params['sms']['sender'], 'route' => Yii::$app->params['sms']['route'], 'mobiles' => $mobileStr, 'authkey' => Yii::$app->params['sms']['authkey'], 'country' => Yii::$app->params['sms']['country'], 'message' => $message, ]; $response = $curl->setGetParams($params)->get(Yii::$app->params['sms']['api_url']); // 记录发送日志,方便后续排查问题 Yii::info([ 'mobiles' => $mobiles, 'message' => $message, 'response' => $response, 'errorCode' => $curl->errorCode, ], 'sms_notification'); return $curl->errorCode === null; }
然后在你的更新逻辑里调用这个方法,轻松添加多组通知:
if ($flag) { $transaction->commit(); // 第一组:给c_apo角色的用户发通知 $apoMobiles = User::find() ->leftJoin('auth_assignment', 'auth_assignment.user_id = user.id') ->select('mobileno') ->andWhere(['auth_assignment.item_name' => 'c_apo']) ->column(); $this->sendSmsNotification($apoMobiles, "Dear Sir, WP {$wpno} is waiting for your approval. Please take necessary steps. Thank You."); // 第二组:给其他角色(比如admin)发通知,按需添加 $adminMobiles = User::find() ->leftJoin('auth_assignment', 'auth_assignment.user_id = user.id') ->select('mobileno') ->andWhere(['auth_assignment.item_name' => 'admin']) ->column(); $this->sendSmsNotification($adminMobiles, "WP {$wpno} has been updated and is pending approval."); // 不管短信发送结果,都跳转到详情页——这才是用户要的最终操作 return $this->redirect(['view', 'id' => $model->wp_no]); }
另外,记得把短信配置移到common/config/params.php里,维护起来更方便:
// common/config/params.php return [ // ...其他配置 'sms' => [ 'authkey' => 'My Auth Code', 'sender' => 'TSTMSG', 'route' => '4', 'country' => '0', 'api_url' => 'http://api.msg91.com/api/sendhttp.php', ], ];
方案2:异步发送短信(推荐,适合通知量大或追求用户体验的场景)
同步发送短信会让用户等待API响应,页面加载变慢。用异步队列的话,用户操作后立即跳转,短信发送任务在后台处理,体验好太多。Yii2的高级模板可以用yiisoft/yii2-queue扩展来实现。
步骤1:安装队列扩展
composer require yiisoft/yii2-queue
步骤2:创建短信发送Job类
在common/jobs目录下新建SmsNotificationJob.php:
namespace common\jobs; use yii\base\BaseObject; use yii\queue\JobInterface; use linslin\yii2\curl\Curl; use Yii; class SmsNotificationJob extends BaseObject implements JobInterface { public $mobiles; public $message; public function execute($queue) { // 同样过滤空手机号和去重 $mobiles = array_filter(array_unique($this->mobiles)); if (empty($mobiles)) { Yii::info('No valid mobiles in queue job', 'sms_notification_queue'); return; } $mobileStr = implode(",", $mobiles); $curl = new Curl(); $params = [ 'sender' => Yii::$app->params['sms']['sender'], 'route' => Yii::$app->params['sms']['route'], 'mobiles' => $mobileStr, 'authkey' => Yii::$app->params['sms']['authkey'], 'country' => Yii::$app->params['sms']['country'], 'message' => $this->message, ]; $response = $curl->setGetParams($params)->get(Yii::$app->params['sms']['api_url']); // 记录队列任务日志 Yii::info([ 'mobiles' => $mobiles, 'message' => $this->message, 'response' => $response, 'errorCode' => $curl->errorCode, ], 'sms_notification_queue'); } }
步骤3:在控制器里推送任务到队列
if ($flag) { $transaction->commit(); // 第一组通知推送到队列 $apoMobiles = User::find() ->leftJoin('auth_assignment', 'auth_assignment.user_id = user.id') ->select('mobileno') ->andWhere(['auth_assignment.item_name' => 'c_apo']) ->column(); Yii::$app->queue->push(new \common\jobs\SmsNotificationJob([ 'mobiles' => $apoMobiles, 'message' => "Dear Sir, WP {$wpno} is waiting for your approval. Please take necessary steps. Thank You.", ])); // 第二组通知推送到队列,按需添加 $adminMobiles = User::find() ->leftJoin('auth_assignment', 'auth_assignment.user_id = user.id') ->select('mobileno') ->andWhere(['auth_assignment.item_name' => 'admin']) ->column(); Yii::$app->queue->push(new \common\jobs\SmsNotificationJob([ 'mobiles' => $adminMobiles, 'message' => "WP {$wpno} has been updated and is pending approval.", ])); // 立即跳转,队列在后台处理短信发送 return $this->redirect(['view', 'id' => $model->wp_no]); }
步骤4:启动队列Worker
最后需要在服务器上启动队列监听进程,比如用命令行:
yii queue/listen
如果是生产环境,建议用Supervisor之类的工具守护这个进程,保证它一直运行。
总结
- 如果通知量小,用方案1就足够,简单直接;
- 如果追求用户体验或者通知量大,方案2的异步队列是更好的选择;
- 不管哪种方案,都要做好日志记录,方便后续排查短信发送问题;
- 把配置抽离到params.php,避免硬编码,维护更轻松。
内容的提问来源于stack exchange,提问作者Alias
相关产品推荐
相关产品推荐

