肯尼亚ip代理联想实验场之微信小程序使用Nodejs+socket.io构建微信客服消息客户端

肯尼亚ip代理近期正在为公司的一个新项目做技术调研,其中一个功能是基于小程序实现门店店员与顾客之间建立消息通路。为了减少安装app带来的成本上升,同时也希望搭上小程序推广红利的快车。于是店员端和顾客端的表现层都使用小程序,消息通路借助的客服消息。另外,本项目的重点是要提升店员的沟通效率,因此,会针对沟通过程中的关键词和产品信息等特点内容做解析(类似于淘宝旺旺的提示功能),方便店员和顾客的浏览。

产品功能点:

1、顾客端,顾客与店员1对1绑定,顾客可以通过小程序肯尼亚ip代理客服消息页面发送消息给绑定的专属店员

2、店员端,接收消息推送、即时消息沟通、离线消息阅读、关键词解析

技术选型思路:

1、即时消息通信:由于小程序支持websocket,因此即时消息这部分优先选择通过websocket实现。在开发语言方面,着重考虑了PHP的swoole和Nodejs的socket.io以及ws。

PHP vs Nodejs:团队目前后端开发使用的是php的laravel,如果使用php搭建websocket服务,那么优选是swoole或者workerman,如果使用Nodejs那么可以选择的工具就会更多一些,其中包括socket.io、node-websocket、faye-websocket-node。于是前端和后端的工程师从以往经验、外界成功经验、可选择框架等几方面做了对比。

a)具体如下表:

语言\对比点PHPNodejs以往经验有成熟经验Js肯尼亚ip代理方面有丰富经验,Node方面略差开发难度一般一般外界成功经验不多较多可选择框架不多多

针对团队目前情况,前端工程师有意愿去尝试新的东西。因此在文档相对完善,社区资源较为丰富的情况下选择了Nodejs。

b)Socket.io vs node-websocket-server vs faye-websocket-node:

在这三个nodejs端的websocket插件中,socket.io的文档和资料最为丰富,node-websocket的也还不错,faye-websocket-node的资料相对较少。因为网上很多关于socket.io的文章中,基本上覆盖了本次项目所涉及的技术点socket.io。

c)Web Server:在web server这部分中,express的文档和相关资料最为丰富,是个不二之选。

d)进程管理:为了解决是nodejs程序最大效率的利用多核cpu,避免因为出错而退出程序。因此在nodejs肯尼亚ip代理之上还需要有一层进程管理程序来对多个进程进行调度。目前主流的方案大多是基于forever和pm2的。这两个插件的功能对比如下:

FeatureForeverPM2Keep AliveYesYesCoffeescriptYesNoLog aggregationYesAPIYesTerminal monitoringYesClusteringYesJSON configurationYes

在本次项目中,考虑到未来在生产环境的部署中可能会遇到的监控、日志、负载均衡等问题,所以选择了pm2。

系统架构设计

负载均衡:这次的架构设计中并没有选择网上的基于nginx ip_hash,而是根据用户的uid尾号进行hash分配。因此这个反向代理层选择了nodejs的http-proxy。代码如下。getServer就是根据uid尾号选取serverslist里面的一台服务器去做反向代理。

Socket.io server同样也是高可用架构,该部分内容主要是参考了它的官方文档。通过增加socket.io-redis肯尼亚ip代理可以在多个socket.io节点中传递事件。

由于本次项目中需要接受来自于的客服消息,因此在处理消息的web服务中还会用到socket.io-emitter。但是由于小编目前处于调研阶段,因此就把socket.io服务和处理消息的web服务放在了一起,当初始话socket服务的时候将变量进行了全局化,这样在整个项目中都可以直接调用。这也是未来在真实的开发中要调整的部分。

消息通信部分:前面提到过在项目中不仅要有实时消息,当用户离线后还需要对离线消息进行存储。于是我使用了redis的pub/sub机制,处理消息的服务器作为pub端,然后每个socket.io server是sub端。为了避免sub肯尼亚ip代理端会重复处理消息,我把消息实体存储在了redis的list中,pub端将消息lpush到list中,然后publish消息,接收到消息的sub端去指定的list中lpop这条信息,并且将信息通过socket.io的emit推送到相应的客户端。如果此时客户端离线,那么sub端将不会去取list中的信息。这样就避免消息被重复处理以及离线消息的存储。

调研中遇到的问题:

问题1:Socket.io服务只有在localhost或者127.0.0.1的情况下才能调用

解决方法:经过排查,是由于服务器的防火墙禁止了除常用的端口外的其他端口,关闭防火墙即可解决

问题2:小程序的websocket无法使用socket.io

解决方法:这个是由于socket.io在使用过程中会给client植入cookie完成验证,而小程序不支持cookie,所以就需要修改socket.io的客户端。修改后的客户端可以通过 来下载。

问题3:如何通过向指定的socket.io客户端发消息

解决方法:ws.sockets.sockets[toSocket].emit(news,data); ws为我的socket.io server的变量。

关于socket.io的身份验证问题会在后续的文章中继续更新。

作者:赵亚东、安庆航