1、关于群发接口和消息接口

关于群发接口
1.订阅号每天可以群发消息一条,服务号每月(自然月)四条的群发权限。开发者模式下,可以通过高级群发接口,实现更灵活的群发能力。
2.注意
● 对于认证订阅号,群发接口每天可成功调用1次,此次群发可选择发送给全部用户或某个标签;
● 对于认证服务号虽然开发者使用高级群发接口的每日调用限制为100次,但是用户每月只能接收4条,无论在公众平台网站上,还是使用接口群发,用户每月只能接收4条群发消息,多于4条的群发将对该用户发送失败;
● 具备微信支付权限的公众号,在使用群发接口上传、群发图文消息类型时,可使用a标签加入外链;
关于客服消息和模板消息接口
当用户和公众号产生特定动作的交互时(具体动作列表请见下方说明),微信将会把消息数据推送给开发者,开发者可以在一段时间内(目前修改为48小时)调用客服接口,通过POST一个JSON数据包来发送消息给普通用户。此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务。
模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等。不支持广告等营销类消息以及其它所有可能对用户造成骚扰的消息。

2、背景

简单的描述一下业务的背景,目前是做一个供求的微信公众号,每当用户付费发送一次供求的信息,我们需要将本条消息推送给所有的用户,这样可以让用户及时收到消息,实现消息的实时性和保证消息的有效性。但是群发的接口根本不能满足我们的需求,于是我们利用模板消息和客服消息的接口来实现我们的需求,在此,有的人可能会发问,为什么客服消息的接收要求这么变态还要利用它呢,其实是因为,群发的消息在某些设备上收到的时候,就像微信好友发送的一条信息,更加吸引用户去关注。
另外,我们还需要知道,假如我们的用户用成千上万的人话,那么群发的方式是十分的耗时的,微信支付提供了notify的异步通知,之前我也一直尝试利用这个现场的异步通知来实现群发,但是根据实际的使用,这个异步IO的阈值差不多在6分钟左右,可是实际上发送一次模板的网络耗时加上数据库的IO其实还是时间还是挺长的,因此我们不得不使用异步多线程来实现我们的群发的功能这里我利用的是swoole的扩展来完成这一需求的。
swoole的异步邮件群发的demo,大家可以参照我的另一篇文章thinkphp5+swoole实现异步邮件群发(SMTP方式)这里可以较为详细的了解服务端和客户端的构建。

3、环境说明

centos7
swoole2.0+
tp5.0+
邮件发送
crontab定时任务

4、实现

4.1创建服务端

我这里就直接贴代码了,需要注意的地方都写在了相关代码的注释,注意看一下

/*** description:服务端*/public function asyncSend(){$serv = new \swoole_server('0.0.0.0', 9090);$serv->set(array('task_worker_num' => 60,'daemonize' => true,'log_file' => '/var/www/html/myswl/tp/swoole.log'));$serv->on('receive', function ($serv, $fd, $from_id, $data) {$task_id = $serv->task($data);echo "开始投递异步任务 id=$task_id\n";});$serv->on('task', function ($serv, $task_id, $from_id, $data) {echo "接收异步任务[id=$task_id]" . PHP_EOL;$data = json_decode($data,true);//这里要特别的说明,我这里用到了数据库的远程链接,因为支付的功能在另一台window虚拟云主机上的,所以不得不利用远程访问的方式。Db::connect($conn,true);的第二个参数给给予关注,因为我们没发送一次其实都会去进行一次远程数据库连接,所以频繁的连接中,肯定会有连接失败的情况,因此我们需要做好断线重连的配置$conn = 'mysql://用户名:数据库远程链接地址:3306/密码#utf8';$db = Db::connect($conn,true);$now = date('Y-m-d H:i:s');$users = $db->table('tp_receiver')->field('openid')->where("(`expire_time` > '{$now}' OR `send_status` = 1 ) AND `receive_status` = 1 ")->limit($data['flag']*500,500)->select();echo $db->getLastSql();echo 'send start--' . date('H:i:s') . PHP_EOL;foreach ($users as $user) {$token = $db->table('tp_accesstoken')->field('accesstoken')->find();
//这里是客服消息$templData2 = array('touser' => $user['openid'],'msgtype' => 'text','text' => array('content' => $data['content']."\n\n点击下方“信息查询”查看更多求购信息。"."\n回复0取消接收信息,回复1重新接收信息"));$res = $this->sendCustomMessage($templData2,$token['accesstoken']);$res = json_decode($res, true);
//判断客服消息是否成功发送if($res['errcode'] == 45047 || $res['errcode'] == 45015) {$templData = array('touser' => $user['openid'],'template_id' => '模板消息','url' => '','data' => array('first' => array('value' => '您好,您收到一条新的提醒', 'color' => '#173177'),'keyword1' => array('value' => '求购信息', 'color' => '#173177'),'keyword2' => array('value' => $data['content'], 'color' => '#173177'),'keyword3' => array('value' => $data['phone'], 'color' => '#173177'),'keyword4' => array('value' => date('Y-m-d H:i:s'), 'color' => '#173177'),'remark' => array('value' => "点击下方“信息查询”查看更多求购信息。"."回复0取消接收信息,回复1重新接收信息", 'color' => '#173177')),);$res = $this->sendTemplateMessage($templData, $token['accesstoken']);Log::write('send to'.$user['openid'].$res . PHP_EOL);}}echo 'send end--' . date('H:i:s') . PHP_EOL;$serv->finish('');});$serv->on('finish', function ($serv, $task_id, $data) {echo 'finish time--' . microtime(true) . PHP_EOL;echo "异步任务[id=$task_id]完成" . PHP_EOL;});$serv->start();}

然后我们在CLI模式下进入项目的根目录,执行

php public/index.php demo/wechat/asyncSend

这样我们的服务端就以守护进程的模式一直运行来我们的后台了,通过ps -aux | grep asyncSend
可以看见,已经有62个进程在处于S(睡眠待唤醒)的状态了,除了60个task进程还用一个master和一个woker进程。

4.2构建客户端

代码如下,需要注意的地方都写在了相关代码的注释,注意看一下

/*** description:客户端*/public function index(){
//因为这个群发比较敏感,我们需要做一个token的机制,我这边就用最简单的发送方和接收方都以明文的方式来做了。$token = $_GET['token'];if($token != 'test'){exit;}
//content是发送的内容,因为不可预估里面的东西,所以进行加解密$content = rawurldecode($_GET['content']);$flag = $_GET['flag'];$id = $_GET['id'];$phone = $_GET['phone'];$data['content'] = $content;$data['flag'] = $flag;$data['phone'] = $phone;Log::write(self::json_encode($data));$insert = ['flag'=>$flag,'miaomu_id'=>$id,'status'=>1,'createtime'=>date('Y-m-d H:i:s'),'content'=>$content];Db::table('task')->insert($insert);//异步客户端$client = new \swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);$ret = $client->connect("127.0.0.1", 9090);
//当无法连接的时候,发送告警邮件if (empty($ret)) {SendMail::postmail('kongwentao@zuihuibao.com','警告','error!connect to swoole_server failed');SendMail::postmail('937069176@qq.com','警告','error!connect to swoole_server failed');Log::write('error!connect to swoole_server failed');} else {$client->send(self::json_encode($data));}}

4.3端口监控

这个群发已经涉及到金额了,所以我们更要关系服务的运行稳定了,这里我们简单的利用crontab定时任务和Php的一些shell相关函数来实现端口的监控。
本次用到的定时任务

*/1 * * * * curl http://你的域名/index.php/demo/Jrmm/checkPortStatus?token=test

就是实现一个每分钟去执行我们下面php代码的一个任务,这里我没有直接用shell来操作,原因有3点,1是我不是很熟悉shell命令,2是我们不太熟悉shell命令,3是写在php里面更方便我去写相关代码和利用已有的一些方法,比如邮件发送。这样虽然多了一点网络资源的消耗,但是也还划算。
具体的监控代码,这边实现的时候会出现很多权限的问题,我就不多说了,遇到的时候自行百度。
/**

 * description:8082服务端口监控*/
public function checkPortStatus(){if (!isset($_GET['token']) || $_GET['token'] != 'test'){exit();}$res1 = exec('sudo netstat -lpn | grep 9090');Log::write($res1);if($res1 == ''){Log::write('9090stop');SendMail::postmail('kongwentao@zuihuibao.com','警告','9090端口服务错误');SendMail::postmail('937069176@qq.com','警告','9090端口服务错误');

//重启我们的服务端,这里需要注意的是,我没有用到swoole提供的平滑重启的功能,很可能会造成数据的丢失,这别额外的需要注意

        exec('sudo php /var/www/html/myswl/tp/public/index.php demo/jrmm/asyncSend');$res = exec('sudo netstat -lpn | grep 8082');if($res != ''){Log::write('9090restart success');SendMail::postmail('937069176@qq.com','警告解除','9090端口重启成功');SendMail::postmail('kongwentao@zuihuibao.com','警告解除','9090端口重启成功');}}
}

4.4实现

我们利用PHP curl函数来模拟一次支付成功后调用我们群发的功能。

$content = 'test';for ($j=0;$j<3;$j++){$url = 'http://你的域名/index.php/demo/Jrmm/index'.'?flag='.$j.'&id=1.'&token=test'.'&phone='110&content='.rawurlencode($content);$this->http_post($url);}
function http_post($url){$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);curl_setopt($ch, CURLOPT_HEADER, 0);$res= curl_exec($ch);curl_close($ch);return $res;
}

为什么循环三次呢,因为我们通过测试发送发送1500次消息的时候,耗时差不多6分钟,但是我们的项目的并发很低,那么就无法充分利用我们开启的60个task进程,所以我们将1500分成三次去发送那么实际上我们消耗了几乎可以忽略不计的网络消耗,让我们的发送的性能提高了三倍多,实际的项目中,发送1500多条实际耗时只要不到两分钟。当然当并发量更大的时候,我们还可以采用队列的方式来处理,这样需要我们队task进程管理更加的熟练。

5、截图

收到的推送消息

告警

发送的日志

利用客服消息和模板消息实现微信群发(突破群发接口的上限)相关推荐

  1. 微信客服消息html链接,微信公众号利用客服消息和模板消息实现微信群发

    1.关于群发接口和消息接口 关于群发接口 1.订阅号每天可以群发消息一条,服务号每月(自然月)四条的群发权限.开发者模式下,可以通过高级群发接口,实现更灵活的群发能力. 2.注意 ● 对于认证订阅号, ...

  2. 小程序客服收不到消息

    前几天帮用户解决了一个问题,记录下 有个用户用我们的芝麻小客服,配置都是正确的,但是一直收不到用户发的消息,无法自动回复消息. 后来发现原来是有bug,如果发现你登陆小程序的客服系统,然后,别人发送消 ...

  3. 【微信开发第二章】SpringBoot实现微信公众号普通消息和模板消息回复

    前言 在进行微信公众号业务开发的时候,微信公众号的消息回复是非常重要的一环,而微信公众号消息回复分为:普通消息自动回复和模板消息回复.该篇文章会先使用微信测试工具过一遍流程,再使用代码进行实现,并且每 ...

  4. 海豚客服系统接入技巧分享:微信端和网页端

    1微信端 1.如何使用微信端原生对话框? 在微信公众平台里设置自定义菜单,设置文字消息,引导客户用原生页面进行问答. 2.公众号接入海豚客服和微信原生客服有什么不同 开通海豚客服账号之后,在第三方客服 ...

  5. 微信公众号利用客服接口主动给用户发送消息的方法

    目前微信并没有放出主动给用户发送消息的接口,但是我们可以使用其多客服接口来达到主动给用户发送消息的目的. 当用户和公众号产生特定动作的交互时(具体动作列表请见下方说明),微信将会把消息数据推送给开发者 ...

  6. 微信小程序客服实现自动回复图文消息链接,点击去关注公众号

    微信小程序开发交流qq群   173683895    承接微信小程序开发.扫码加微信. 用户打开客服消息,发送任意消息自动回复图文链接,达到关注公众号的目的. 先看效果: 打开芝麻小客服的后台,选择 ...

  7. 微信公众号客服系统怎么实现消息提醒,快速回复粉丝留言?

    很多做微信公众号运营的小编,都会有这样的工作经验吧,一上班就开始刷新微信公众号后台,看看有没有粉丝留言,然后这一天就开始了时不时打开后台页面看一下,即使这样还是免不了粉丝留言晚回或者漏回的情况发生,追 ...

  8. 融云客服获取未读消息

    比较极客的我们 能动手的尽量少BB 这里主要介绍两个API getUnreadCount setOnReceiveMessageListener 思路:为 setOnReceiveMessageLis ...

  9. java在线网页客服聊天_管理员消息java 网站用户在线和客服聊天

    首先声明,我是一个菜鸟.一下文章中出现技术误导情况盖不负责 这是应用到项目中的一个例子. 实现原理是将信息存储到Application域里面.然后应用Struts2 Action 用json格式的数据 ...

最新文章

  1. 一位中学计算机老师的英语作文,我的老师英语作文(精选14篇)
  2. VTK与ITK的详细安装指南
  3. openshift介绍及centos7安装单节点openshift、Redhat安装openshift集群完全教程
  4. 6-6 归并排序(递归法) (10分)
  5. 简明介绍java“包”的用法
  6. oracle报错12516,Oracle连接数太多报错-ORA-12516异常
  7. Linux常用监控服务器性能命令 内存 CPU 磁盘
  8. Debian系统关闭iptables的conntrack跟踪
  9. vlc android tv版,VLC播放器电视版本v1.6.0 Android版本
  10. PCB 设计流程(allegro 为例)
  11. 删除双系统遗留的efi
  12. 轻量级分布式事务-自定义多数据源事务注解
  13. web前端关于浏览器兼容性
  14. Kotlin学习(二十): Kotlin实现流的读取的方案
  15. 欧式距离与曼哈顿距离的区别以及曼哈顿距离的应用
  16. 2023年CSS面试题集合
  17. matlab的imresize函数,为什么python cv2.resize函数对RGB图像给出的结果与MATLAB imresize函数不同?...
  18. 6.PCIe协议分析3-PCIe TLP包详解2
  19. ZZULIOJ 2348: 小明的第一份实习任务(前缀和)
  20. 【OI向】快速傅里叶变换(Fast Fourier Transform)

热门文章

  1. OSCP学习笔记总结(本资料禁止转载)
  2. Network Saboteur/网络破坏者
  3. React实现登录功能
  4. 碳性9V电池的内部结构
  5. android语言列表+波斯,android怎么添加一种新语言
  6. 昨天看了一场尤雨溪的直播,聊聊过程和感受
  7. 向外行介绍程序员工作的复杂程度
  8. 中国人才开始知道“维密秀”,它就要取消了?
  9. linux下使用ccat让你的cat高亮显示
  10. javaScript 显示图片的例子