,

在 Web 应用中,触发后台异步批量发送短信并确保不影响用户体验,通常可以通过异步任务处理来实现。具体实现的方法有很多种,主要目的是让前台用户在请求发送短信时,不会因为短信发送过程的延时而卡住页面,从而影响用户体验。

以下是一个常见的解决方案,利用 后台异步处理队列机制 来完成这一任务。

解决方案概述

  1. 前端:触发一个请求来发起短信任务。
  2. 后端:接收到请求后,将短信任务入队(异步处理),然后立刻返回给前端,告诉用户请求已提交,正在处理中。
  3. 任务队列:后台服务从队列中读取任务,异步批量发送短信。
  4. 用户体验:由于是异步任务,用户不会被阻塞,前端页面可以继续操作,甚至在后台任务完成后通过 WebSocket轮询 来通知用户短信发送结果。

具体实现

1. 使用队列系统处理短信任务

通过 队列系统,你可以将所有短信发送任务加入队列,后台 worker 会异步消费队列中的任务并执行批量发送。常用的队列系统有 Redis QueueRabbitMQLaravel Queue 等。

示例:使用 Redis Queue 处理短信发送任务
  • 前提:需要安装和配置 Redis 和队列服务。
  • 步骤
    1. 在前端触发请求,告诉后端开始短信发送。
    2. 后端将任务加入队列。
    3. 后台的 worker 会从队列中消费任务,并开始批量发送短信。
前端代码:触发后台请求
// 假设你有一个触发按钮来发送批量短信
document.getElementById('sendSmsButton').addEventListener('click', function() {
    fetch('/api/send-bulk-sms', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ phoneNumbers: ['12345678901', '9876543210'], message: 'Hello World' })
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            alert('短信发送任务已提交,稍后会处理!');
        } else {
            alert('任务提交失败,请稍后重试!');
        }
    });
});
后端代码:处理短信发送请求并入队任务(使用 Laravel 框架为例)
// routes/web.php
Route::post('/api/send-bulk-sms', 'SmsController@sendBulkSms');

// SmsController.php
use App\Jobs\SendBulkSms;

class SmsController extends Controller
{
    public function sendBulkSms(Request $request)
    {
        // 获取前端请求的电话号码和消息内容
        $phoneNumbers = $request->input('phoneNumbers');
        $message = $request->input('message');
        
        // 将发送短信的任务加入队列
        SendBulkSms::dispatch($phoneNumbers, $message);

        return response()->json(['success' => true, 'message' => '短信发送任务已提交']);
    }
}
队列任务:SendBulkSms 任务类
// app/Jobs/SendBulkSms.php
namespace App\Jobs;

use App\Services\SmsService; // 你的短信服务类
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class SendBulkSms implements ShouldQueue
{
    use InteractsWithQueue, Queueable, SerializesModels;

    protected $phoneNumbers;
    protected $message;

    // 构造函数接收短信相关的参数
    public function __construct($phoneNumbers, $message)
    {
        $this->phoneNumbers = $phoneNumbers;
        $this->message = $message;
    }

    // 任务处理方法,发送短信
    public function handle(SmsService $smsService)
    {
        foreach ($this->phoneNumbers as $phone) {
            // 假设 SmsService 已经封装了短信发送的逻辑
            $smsService->send($phone, $this->message);
        }
    }
}
后台消费任务

确保你已经配置并启动了队列消费服务。例如,在 Laravel 中,可以使用 php artisan queue:work 来启动队列消费者。

php artisan queue:work

这样,队列中的任务就会被后台的 worker 消费并执行。通过 SendBulkSms 任务类中的 handle() 方法,你可以批量发送短信,而不会影响用户体验。

2. 确保后台任务不会阻塞

为了确保后台任务不会阻塞,可以通过以下方式处理:

  1. 异步任务处理:使用队列系统如 Redis QueueRabbitMQBeanstalkd 等来处理短信任务。这些队列系统会在后台线程中处理任务,不会占用主线程。
  2. 分批次处理:如果短信数量非常大,最好将发送任务分批处理,每次处理一定数量的短信,避免一次性任务超时或导致资源紧张。

3. 通知用户短信发送状态

为了保持用户体验,你可以通过以下两种方式通知用户:

3.1 使用 轮询

在前端页面上定期检查短信任务的处理状态。如果任务完成,向用户显示成功消息。

function checkSmsStatus(taskId) {
    setInterval(function() {
        fetch('/api/sms-status/' + taskId)
            .then(response => response.json())
            .then(data => {
                if (data.status === 'completed') {
                    alert('短信已发送完成!');
                }
            });
    }, 5000); // 每5秒轮询一次
}

3.2 使用 WebSocket

通过 WebSocket 通知前端短信发送的进度或结果。这种方式比轮询更高效,因为它是实时推送的。

  • 在后台任务处理过程中,可以通过 WebSocket 向前端推送消息通知。
  • 使用 Laravel WebSocketsSocket.io 等工具来实现。

4. 总结

通过使用队列系统(如 Redis Queue 或其他消息队列)来异步处理短信任务,你可以确保:

  • 用户请求一发起,立即返回处理结果,而不会阻塞用户界面。
  • 后台异步发送短信时,不会影响用户体验。
  • 可以通过轮询或 WebSocket 实时向用户反馈短信发送状态。

这种设计可以显著提高用户体验,避免长时间的请求阻塞和页面卡顿。