宝哥软件园

用ThinkJs搭建微信中控服务的实现方法

编辑:宝哥软件园 来源:互联网 时间:2021-08-21

我有个前端人渣。这篇文章是第一次写。如果有硬核bug,请轻喷指出.此外,本文不涉及任何接口安全、参数验证等。默认情况下,调用者没有大脑级别的信任。joy:当前的自用界面包括但不限于以下内容

|-微信相关| |-0。处理一些微信推送的消息| |-1。获取微信SDK配置参数| |-2。微信认证登录| |-3。获取微信用户信息| |-4。获取AccessToken| | - 5。成批发送模板消息

【需求】小项目很多,大部分需求都是基于微信开发的。如果每次查微信文档,都会很郁闷。未修改:【有很多】微信官方账号,偶尔项目涉及到借用权限获取用户信息(在不绑定微信开放平台的前提下,需要临时搭建每个微信官方账号的openid关联关系)。同时,如果一个以上的微信官方账号需要合作才能满足一件事的需求,很容易让人产生困惑.【支付】微信支付的商户号很多,有时需要用于支付的商户号,关联微信官方账号取出的openid无法支付.【官方】微信公文建议!将接入令牌和其他微信应用编程接口收回到单独的服务中.等等.因此.joy:创建ThinkJS项目。

官方网站

thinkjs.org/

简介

ThinkJS是一个面向未来的Node.js框架,它集成了大量的项目最佳实践,让企业级开发变得如此简单高效。从3.0开始,框架底层基于Koa 2.x,兼容Koa的所有功能。

安装脚手架

$ npm install -g think-cli来创建和启动项目

$ thinkjs新演示;$ cd演示;$ npm安装;$ npm开始;目录结构

| -开发环境中的development.js//entry文件| - nginx.conf //nginx配置文件|-package.json |-PM2.json//PM2配置文件|-production . js//生产环境中的entry文件|-readme . MD |-src | |-bootstrap//启动自动执行目录| | | |-master.js//master进程下的自动执行| |-worker.js//worker进程下的自动执行| |-config//配置文件目录| |-adapter.js. Adapter配置文件| |-config . js//默认配置文件| | |-config . production . config . config与config.js合并| | | - extend.js //extend配置文件| | -middleware . js//中间件配置文件| | |-router . js//自定义路由配置文件| |-controller//controller目录| | |-base . js | |-index . js | |-logic//logic目录| | | - index.js| | - model ///model目录| | | - index.js| - view ///template目录| |-。

介绍

微信中间件,基于node-webot/微信,支持thinkJS 3.0

装置

$ npm安装思维-微信-保存或

$ cnpm安装think-微信-保存配置

文件:/src/config/middleware.js

Const微信=必选(' think-微信')模块。出口=[.{handle:微信,match:'/index ',选项: {token : ' ',//token,写的和微信官方账号/基本配置/服务器配置一样,就是appid: ' '。//好像可以随便填,因为我们会用数据库配置几个微信官方账号encodingasekey : ' ',checksignature: false}},{handle:' payload ',//think-微信必须在payload中间件前面加载,payload中间件会处理微信发送的post请求中的数据,而不是payload。选项: {保留扩展名:为真,限制:' 5mb'},]注意:我在match下这里写/index,对应的项目文件是/src/controller/index.js,对应的微信官方账号后台需要配置的服务器地址是http(https)://域名3360端口/index

创建数据库和相关表

我在这里创建了三个相关的微信表格。

配置表:wx_config

字段类型描述id int主键名varchar name appid varchar appid secret varchar secret用户表:wx_userinfo

字段类型备注id int主键订阅int用户是否订阅微信官方账号id。当值为0时,表示用户没有关注微信官方账号,无法拉取剩余信息。昵称varchar用户的昵称sex int用户的性别,值1为男,值2为女,当值为0时,是headimgurl longtext用户在未知语言varchar用户所在省份的头像,省varchar用户所在城市,国家varchar用户所在国家,最后一个值代表方形头像的大小(0,46,64,96,132可选,0代表640*640方形头像)。如果用户没有头像,此项为空。如果用户更改头像,原头像网址将无效。Subscribe_time双用户关注时间,这是一个时间戳。如果用户已经关注了很多次,以最后一次关注为准。unionid varchar只有在用户将微信官方账号绑定到微信开放平台账号后,该字段才会出现。Openid varchar用户id,以及当前微信官方账号中唯一wx_config_id int对应的微信号id模板消息日志表:wx_template_log

字段类型注释id int主键template _ id varchar template id open id varchar用户id,Send content JSON string add _ time double add timestamp Send _ time double Send timestamp Send _ status varchar Send result wx _ for唯一url varchar跳转url miniprogram varchar跳转小程序在微信官方账号Config_id double中对应配置的微信号id uuid varchar。业务系统可以通过uuid查询模板消息推送结果来处理微信推送消息

文件目录

/src/controller/index.js文件内容

模块。出口=阶级延伸思考.控制器{/* * *入口:验证开发者服务器* 验证开发者服务器,这里只是演示,所以没做签名校验,实际上应该要根据微信要求进行签名校验*/async indexAction(){ 0让那个=这个;if (that.method!=' REPLY '){返回那个。JSON({代码: 1,msg: '非法请求,数据: null })} const { echostr }=该。get();返回。end(echostr);} /* * 文字* 用于处理微信推过来的文字消息*/async TextAction(){ 0让那个=这个;让{id,签名,时间戳,nonce,OpenID }=那个。get();让{用户名,发件人用户名,创建时间,MsgType,内容,MsgId }=那个。post();那个。成功(')}/* *事件* 用于处理微信推过来的事件消息,例如点击菜单等*/async EventAction(){ 0让那个=这个;让{id,签名,时间戳,nonce,OpenID }=那个。get();让{用户名,发件人,用户名,创建时间,MsgType,事件,事件键,票证,纬度,经度,精度}=那个。post();switch(Event){ case ' subscribe ' ://关注公众号.打破;案例"取消订阅": /取消关注公众号.打破;案例SCAN': //已关注扫码.打破;案例“LOCATION”://地理位置.打破;案例点击' : //自定义菜菜单.打破;案例视图' : //跳转.打破;案例" TEMPLATESENDJOBFINISH"://模版消息发送完毕.打破;}那个。成功(')} }注:支持的行为包括:文本动作、图像动作、语音动作、视频动作、短视频动作、位置动作、链接动作、事件动作、设备文本动作、设备事件动作。

公众号后台配置

注:后面跟的编号参数是为了区分是哪个公众号推过来的消息,在上面的接口参数中也有体现

微信相关应用程序接口的编写

目录结构

| - src| | -控制器//控制器目录| | | - index.js //处理微信推送的消息,上面有写到| | | - common.js //一些公共方法| | | -打开/开放给其他业务服务的美国石油学会(美国石油协会)接口| | | | - wx.js| | | - private //放一些内部调用的方法,调用微信美国石油学会(美国石油协会)的方法主要在这里面| | | | - wx.js这个目录结构可能不太合理,后期再改进吧:格林:

公共方法

//src/控制器/公共。jsimport axios从“axios”导入{ baseSqL }从./unit ';模块。出口=阶级延伸思考.控制器{ //获取访问异步getWxConfigById(id) { let那=这个让数据=等待。缓存(` wx _ config : wxid _ $ { id } `),async ()={ //数据库内取让信息=等待。模型(' wx _ config ',baseSql).其中({id: id}).find();if(!好好想想。isempty(info)){ return info } })返回数据|| {} } //获取access _ token async GetAccessToken(id){ let that=this;让访问令牌=等待。cache(` wx _ access _ token : wxid _ $ { id } `),async ()={ let {appid,secret }=等待。getwxconfigbyid(id);让{数据}=等待axios({ method: 'get ',URL : `https://api.weixin.qq.com/cgi-bin/token?grant _ type=client _ credential appid=$ { appid } secret=$ { secret } ` });返回数据。access _ token });返回访问令牌}}接口过滤器

所有开放出来的接口的前置方法,俗称过滤器?所有开放的接口必传得到参数是wxid,对应数据库表wx_config里面编号

//src/controller/open/wx。js async _ _ before(){让那个=这个;让wxid=那个。get(' wxid ');如果(想想。isempty(wxid)){返回那个。JSON({代码: 1,msg: 'wxid不存在})}那个。Wxconfig=等待。控制器(“通用”).getWxConfigById(wxid);如果(想想。我是空的。wxconfig)){返回那个。JSON({代码: 1,msg: 'wxid不存在'}) }}接口-获取访问令牌

代码

//src/controller/open/wx。jsasync get _ access _ token action(){ 0让那个=这个;让accessToken=等待。控制器(“通用”).getAccessToken(即。wxconfig。id);返回那个。json({code: 0,msg: ' ',data : { access _ token : access token } })文档

接口-获取微信软件开发工具包的配置

代码

//src/controller/open/wx。jsasync get _ wxsdk _ config操作(){ 0让那个=这个;让{ URL }=那个。get();如果(想想。isempty(URL)){返回那个。JSON({代码: 1,msg: '参数不正确}) }让sdkConfig=等待。控制器(“私有/wx”).getSdkConfig(即。wxConfig.id,URL);返回那个。json({code: 0,msg: ' ',data : sdkConfig })}//src/controller/private/wx。jsconst sha1=必选(' sha1 ');const getTimestamp=()=parsent(date。now()/1000)const getNonceStr=()=math。random().toString(36).substr(2,15)const getSignature=(参数)=sha1(对象键(参数)。排序()。map(key=` $ { key。tolowercase()}=$ { params[key]} `).联接(" ");async getSdkConfig(id,URL){ let that=this;让{appid}=等待那个。控制器(“通用”).getWxConfigById(id);让share config={ non crest : getnon crest()、jsapi_ticket:等待。getjsapticket(id)、timestamp: getTimestamp()、url: url }返回{ appId: appid、时间戳:共享配置。时间戳、非佳洁士:共享配置。非佳洁士、签名3360 getSignature(共享配置)} }文档

接口-获取用户信息

代码

//src/controller/open/wx。js异步get _ UserInfoAction(){ 0让那个=这个;让{ OpenID }=那个。get();如果(想想。isempty(OpenID)){返回那个。JSON({代码: 1,msg: '参数不正确}) }让userInfo=等待。控制器(“私有/wx”).getUserInfo(即。wxConfig.id、open id);如果(想想。isempty(UserInfo)){返回那个。JSON({代码: 1,msg: 'openid不存在,data: null}) }返回that.json({code: 0,msg: ' ',data : UserInfo })}//src/controller/private/wx。jsasync GetUserInfo(id,OpenID){ let that=this;让UserInfo=等待。缓存(` wx _ UserInfo : wxid _ $ { id } : $ { OpenID } `),async ()={ //先取数据库让model=that.model('wx_userinfo ',base SqL);让UserInfo=等待模型。其中({ wx _ config _ id :openid: openid}).find();if(!好好想想。isempty(userInfo)userInfo。subscribe==1 userInfo。工会id!=null){ 0返回userInfo } //如果数据库内没有,取新的存入数据库让accessToken=等待。控制器(“通用”).getAccessToken(id);让网址=`https://api.weixin.qq.com/cgi-bin/user/info?access _ token=$ { access token } OpenID=$ { OpenID } lang=zh _ cn `;让{ data }=wait axios({ method : ' get ',URL : URL });if (data.openid) { //命中修改,没有命中添加让resId=等待模型。然后更新(对象。assign(data,{ wx _ config _ id : }),{openid: openid,wx _ config _ id : });返回等待模型。其中({ id : ReSid }).find();} })返回用户信息}文档

接口-批量发送文字客服消息

代码

//src/controller/open/wx。js异步发送_ msg _ TextAction(){ 0让那个=这个;让{ list }=那个。post();如果(想想。isempty(list)){返回那个。JSON({代码: 1,msg: '参数不正确}) }那个_ sendMsgTextList(即。wxConfig.id,list);返回that.json({code: 0,msg: ' ',data : null })} async _ sendmaskegxtlist(wxid,list){让that=this让apiWxController=那个。控制器(' private/wx ');for(let item of list){ let data=wait apiwxccontroller。sendmasgtext(wxid,item.openid,item。text)}//src/controller/private/wx。jsasync sendmasgtext(id,openid,content){ let that=this;让accessToken=等待。控制器(“通用”).getAccessToken(id);让网址=`https://api.weixin.qq.com/cgi-bin/message/custom/send?access _ token=$ { access token } ` let { data }=wait axios({ method : ' post '、url: url、data: {'msgtype': 'text '、touser': openid、' text ' : { ' content ' : content } })返回数据;}文档

写在最后

其实有很多接口,这里不一一列举。

需要明确的是,在这个项目中,不仅仅是微信界面简单转发,还有一些自己的处理逻辑在里面。

比如在获取微信用户信息时,首先会判断是否有缓存,如果没有,就拿数据库来说,如果还没有去微信界面;如果数据库存在,相关字段不关注,还是会调用微信界面拍一波,重新更新。反正一天之内,微信界面的通话次数绝对够用。

比如批量发送模板消息时,中控服务会在收到请求后先创建一个uuid,将所有要发送的模板消息保存在数据库中,直接将uuid返回给调用者。然后,中央控制将异步使用uuid来检索这些模板消息,逐个发送,并逐个更新结果。这样,服务端调用发送模板消息后,就不需要等待所有消息都发送了,可以使用uuid在中控中查询本次批量发送的状态结果。

目前有七八个微信官方账号并列。在不烧香的前提下,一直没有问题

以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

更多资讯
游戏推荐
更多+