前言
基于 Electron + Node.JS + 小程序 实现弹幕小工具 (开篇)
基于 Electron + Node.JS + 小程序 实现弹幕小工具 (上篇)
上两篇文章, 分别对产品需求和 Electron 端的实现做了相关的介绍, 有兴趣的朋友可以看看之前的文章. 本文, 将介绍服务端的实现.
需求分析
之前的文章也有提到, 服务端的主要任务是对数据进行转发以及生成小程序二维码.
对数据进行转发, 主要是把用户在小程序端发送的消息, 推送给 Electron 接收端. 因此, 我们需要创建一个 websocket 服务. 在这里, 我们选择使用 ws 模块.
生成小程序二维码, 我们需要使用到微信的 API. 我们将使用 request 这个模块向微信服务器发起相关的请求.
创建 websocket 服务
入口文件代码如下:
- const WebSocketServer = require('ws').Server;
- const port = require('./config').port;
- const log4js = require('./helpers/logger');
- const logger = log4js.Logger('APP');
- const wsServer = new WebSocketServer({ port });
- logger.info("Server listening on port:" + port);
- wsServer.on('connection', function (ws) {
- logger.debug('a client connect');
- ws.on('message', async function (message) {
- // 消息处理逻辑
- });
- ws.on('close', function () {
- logger.info('ws 断开');
- })
- ws.on('error', function (error) {
- ws.close();
- logger.error(error);
- })
- });
连接上这个服务的客户端, 有可能是小程序发送端, 也有可能是 Electron 接收端, 所以我们需要对收到的消息进行了简单的类型判断.
根据之前的约定, 如果消息的类型 type 为 INIT, 我们就认为是接收端初始化的消息. 传递的参数中, 包含接收端的 UID, 我们将会使用这个 id 作为参数, 生成带参数的小程序二维码.
由于我们会在公众场合使用弹幕, 所以我们需要对内容进行校验, 防止一些不符合社会主义核心价值观的言论出现在弹幕中. 这里, 我们直接使用微信的接口.
- ws.on('message', async function (message) {
- try {
- const data = JSON.parse(message);
- if (data.type === "INIT") {
- logger.info('获取二维码', data);
- // 将接收端的 clientId 作为连接的标识
- ws.danmuId = data.clientId;
- // 获取微信小程序二维码
- const result = await WechatService.getQrcode(data.clientId);
- if(result){
- const respMsg = {
- type: 'qrcode',
- data: result
- }
- ws.send(JSON.stringify(respMsg));
- }
- } else {
- logger.info('收到消息', ws.danmuId, message);
- // 对消息内容进行安全性校验
- const isSecurity = await WechatService.checkContentSecurity(data.content);
- if(isSecurity){
- // 将消息转发给对应的接收端
- wsServer.clients.forEach(function (client) {
- if (client.danmuId === data.scene && client.readyState === 1) {
- client.send(message);
- }
- });
- }
- }
- } catch (error) {
- logger.error(error);
- }
- });
生成带参数的小程序二维码
微信提供生成二维码的接口有三个, 分别应用于不同的应用场景. 具体见小程序官方文档
本项目使用 getWXACodeUnlimit 这个 API 来获取小程序码, 通过该接口生成的小程序码, 永久有效, 数量暂无限制.
请求地址
POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
如果调用成功, 会直接返回图片 *** 二进制内容 ***, 如果请求失败, 会返回 JSON 格式的数据.
WTF, 官方文档说了, 会返回二进制的内容, 但是为什么我的请求返回乱码呢?
既然乱码, 那应该就是编解码的问题了, 看看所用的请求模块 request 是否有相关的参数设置, 果不其然:
encoding - encoding to be used on setEncoding of response data. If null, the body is returned as a Buffer. Anything else (including the default value of undefined) will be passed as the encoding parameter to toString() (meaning this is effectively utf8 by default). (Note: if you expect binary data, you should set encoding: null.)
默认是 utf8, 如果我们需要二进制内容, 那需要将 encoding 设置为 null. 结果输出如下:
看起来是好点了, 我们通过 Buffer 的 toString 方法将其转为 base64, 然后传给 Electron 端进行展示, 生成二维码的功能就完成了.
access_token 获取与缓存
有微信开发经验的朋友都知道, 基本上所有的微信 API, 请求的时候都需要带上 access_token. 而每天请求 access_token 的次数是有限制的, 超出一定的限制则无法获取, 只能坐等明天的到来. 所以我们需要对 access_token 进行缓存.
由于我们的项目是单机部署, 所以我们可以简单处理, 将 access_token 存在内存中, 每次先判断内存中的 access_token 是否过期, 未过期则使用, 反之则向微信服务器请求最新的, 并同步更新到内存中.
如果考虑多实例部署, 可以将 access_token 存储到 Redis 中.
日志打印
鲁迅曾经说过, 没有打印日志的服务都是耍流氓. 日志, 是后台服务不可或缺的一部分, 这里我们使用 log4js 进行日志的打印.
最简单的使用示例:
- var log4js = require('log4js');
- var logger = log4js.getLogger();
- logger.level = 'debug';
- logger.debug("Some debug messages");
详情请查看官方文档 https://www.npmjs.com/package/log4js
GitHub 项目地址
项目地址 https://github.com/BlackGoldTeam/danmu666
我们将陆续整理各端的代码放在 GitHub 上, 有兴趣的可以查阅一下.
总结
本文使用 ws 模块搭建了一个简单的 websocket 服务, 并使用 request 进行微信 API 的请求, 用于获取小程序码等. 在日志打印方面, 我们使用 log4js, 记录一些关键信息.
下一篇文章, 我们将会探讨小程序端的实现.
以上, 如有错漏, 欢迎指正!
@Author: TDGarden
来源: https://juejin.im/post/5bfbea396fb9a049c2321c5e