You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:58:54