叶子现在公司的框架用的Laravel,众所周知,用Laravel就是为了优雅的实现需求。但是,以当下架构和需求。实在是优雅不来了。实现需求才是优先。

今天要说的是,微信发送公众号模板消息踩到的大坑之路。虽然目前也不确定是否已经排除了Bug。

首先我们来看一下环境:

框架:Laravel 5.5

后台框架:Laravel-Admin 1.7.14

PHP版本:7.3

Redis版本:6.0.9

EasyWechat:~4.0

最原始的版本,不走队列的情况下,直接强撸到底,直接在对应位置写如下代码:


$open_id = 'xxxxxxxxxxxxxxxxxxx';
$app = app('wechat.official_account');
$app->template_message->send([
'touser' => $open_id,
'template_id' => WX_TEMPLATE_ID,
'url' => 'https://xxxxx.xxx',
'data' => [
'first' => 'Title',
'keyword1' => 'ProjectTitle',
'keyword2' => '项目状态',
'keyword3' => '项目状态信息',
'keyword4' => date('Y-m-d H:i:s'),
'remark' => '进度将通过此公众号持续推送,请持续关注!',
],
]);

按照原来的这个方法,出现了一个问题,同样的代码的情况下,每次发送模板消息,腾讯回调的都是发送成功,得到如下Log:


HTTP/1.1 200 OK 
Connection: keep-alive 
Content-Type: application/json; 
encoding=utf-8 
Date: Mon, 21 Dec 2020 07:28:30 GMT 
Content-Length: 55  
{"errcode":0,"errmsg":"ok","msgid":1659995462566756352}

回调是成功了,但是用户经常会出现没有收到推送消息的情况。腾讯方面回复的是:可能是发送的信息里包含了特殊字符或表情之类的,也有可能是用户多端登录导致。

但是经过叶子的几次测试,多端登录并不会影响信息的接收,从发送日志里提取没有收到的信息进行手动单独发送,也是可以正常接收信息的。那么客服的几个假设问题就都不存在了。就在没有头绪的时候,只能考虑是不是短时间内发送的次数太多,被腾讯方面给吞了请求。为了减少同一时间内发送次数太多的问题,叶子就想到了走延时队列。于是就开始了如下操作:

首先,创建Jobs,


php artisan make:job SendWechatMessage

创建后得到如下文件,并进行逻辑编写:

<?php

namespace App\Jobs;

use Exception;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Facades\Log;

class SendWechatMessage implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $params;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($params)
    {
        $this->params = $params;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $data = $this->params;
        if(!isset($data['url']) || empty($data['url'])){
            Log::error('微信队列:缺少URL');
            return false;
        }
        if(!isset($data['open_id']) || empty($data['open_id'])){
            Log::error('微信队列:缺少OPENID');
            return false;
        }
        if(!isset($data['first']) || empty($data['first'])){
            Log::error('微信队列:缺少FIRST');
            return false;
        }
        if(!isset($data['keyword1']) || empty($data['keyword1'])){
            Log::error('微信队列:缺少keyword1');
            return false;
        }
        if(!isset($data['keyword2']) || empty($data['keyword2'])){
            Log::error('微信队列:缺少keyword2');
            return false;
        }
        if(!isset($data['keyword3']) || empty($data['keyword3'])){
            Log::error('微信队列:缺少keyword3');
            return false;
        }
        if(!isset($data['keyword4']) || empty($data['keyword4'])){
            Log::error('微信队列:缺少keyword4');
            return false;
        }
        $app = app('wechat.official_account');
        $res = $app->template_message->send([
            'touser' => $data['open_id'],
            'template_id' => WX_TEMPLATE_ID,
            'url' => $data['url'],
            'data' => [
                'first' => $data['first'],
                'keyword1' => $data['keyword1'],
                'keyword2' => $data['keyword2'],
                'keyword3' => $data['keyword3'],
                'keyword4' => $data['keyword4'],
                'remark' => '进度将通过此公众号持续推送,请持续关注!',
            ],
        ]);
        if($res['errcode'] == 0){
            Log::info('微信队列发送成功!');
        }else{
            Log::info('微信队列发送失败!');
        }
    }

    public function failed(Exception $exception)
    {
        Log::error('[微信队列执行失败:'.date('Y-m-d H:i:s').']');
    }
}

然后在对应位置调用dispatch进行任务分发并且delay,代码如下:

$params = [];
$params['open_id'] = $sm_open_id;
$params['url'] = 'https://xxx.com/list?status=4';
$params['first'] = '项目进度更新!';
$params['keyword1'] = '项目名称';
$params['keyword2'] = '项目状态';
$params['keyword3'] = '提示信息!';
$params['keyword4'] = '操作时间';
SendWechatMessage::dispatch($params)->onQueue('wechatmessage')->delay(now()->addSeconds(10));

delay及延迟时间,使用了carbon,now()->addSeconds(10),这个命令就是在当前时间上延迟10秒执行。当然这个延迟队列可以用在很多场景里。大家根据自己的需求去做调整。

做了如上操作后。目前为止暂未有反馈说未收到信息。就坐等测试一波吧。

P.S.:本文仅来自博主本人菜鸟记录,欢迎大神指教。