- 上一篇传送门—— 微信公众号 | API连接篇
- 本次工程项目在 https://gitee.com/ayachensiyuan/wechat_server 代码仓库中更新
本篇的主题
- 模块化整理
模块化的优势
随着项目不断复杂,功能不断增多,如果代码全都放在app.js中势必后期维护起来变得极其困难。在准备新的功能前必须要重新规整代码,按照业务逻辑封装你的代码是程序员良好的习惯。
js是一种脚本语言,理论上说js中“万物皆对象”,甚至基本数据结构也是在c++的基础上封装后的对象。js的对象并不具有底层“对象”的意义,但是我们操作它们还是应该保持操作底层对象的逻辑。
设计思路
express的中间件是很优秀的设计,这就相当于一个管道,数据通过层层管道,只会在对应的管道中停下处理,这好比邮件的分拣中心,包裹从统一的入口进入传送带,最后被传送到不同的出口。
参考文档:
https://www.expressjs.com.cn/guide/using-middleware.html
譬如我这边把路由作为一个传送带的一个管道,再细分下,这个路由管道的’/wx’就是一个分管道之一,再细分’GET’,'POST’等又是一层更小的管道,再再细分如’POST’处理’text’和’image’又会进入新的管道。还能细分就是’text’处理每种文字又会进入更更细的管道。这种从顶至下不断细分的管道能使业务逻辑变得清晰,同时也能避免if else嵌套。代码分文件储存,如果问题出在哪里就能直接定位到最细的那一个模块中。
有一种设计模式叫”开闭原则“,对扩展开放,对修改封闭。当业务有新的需求时候,不需要修改原来的代码,只要添加新的处理管道连接上最终的主管道即可。这种管道的思路恰好能符合这样的设计思路。
项目文件分类
以下是项目重新构建的目录
- middleware文件夹中放置所有中间件
- tools文件夹中放置所有工具函数
- middleware文件夹按照逻辑继续细分
- 管道的最后需要统一处理没有配置的请求写在errorHandler.js文件中
这样的好处就是所有业务分模块分文件储存,哪里错了改哪里,以最小代价影响其他模块性能;同样要新增功能也很直观,按照业务逻辑进入不同的管道来添加新的处理中间件代码。
代码详细
- 首先是app.js入口文件,原先都写在这一个文件里很乱,现在再看下效果:
//app.js
const express = require('express')
const app = express()
//验证服务器中间件
app.use(require('./middleware/verifyServerRouter'))
//消息预处理中间件
app.use(require('./middleware/paseMsgMW'))
//消息服务中间件
app.use(require('./middleware/messageRouter'))
//处理未知情况返回404
app.use(require('./errorHandler'))
app.listen('3000', () => {
console.log('server started at port 3000')
})
- 中间件文件
我就不一一展示每个路由,大家可以在代码仓库查看代码,这里展示几个典型的文件:
//parseMsgMW.js
//消息预处理中间件
const parseMsgMW = require('express').Router()
parseMsgMW.route('/wx')
.post(async (req, res, next) => {
//消息预处理
const xmlMsg = await require('../tools/getUserMessage')(req)
const jsonData = await require('../tools/paresMsg')(xmlMsg)
//信息放入req中继续传递
req.jsonData = jsonData
//传递到下一个中间件处理
next()
})
module.exports = parseMsgMW
//msgRouter.js
const msgRouter = require('express').Router()
// 处理系统消息
msgRouter.use(require('./messageDelling/sysMsgMW'))
// 最后处理文字消息
msgRouter.use(require('./messageDelling/textMsgMW'))
module.exports = msgRouter
//dailyVerseMW.js
const dailyVerseMW = require('express').Router()
dailyVerseMW.route('/wx')
.post((req, res, next) => {
if (req.jsonData.MsgType[0] == 'text') {
const { jsonData } = req
//发送每日经文
if (jsonData.Content[0] == '每日经文') {
const axios = require('axios')
//使用axios来处理请求
axios.get('http://127.0.0.1:3001/api/getDailyVerse').then(response => {
//使用sendMsg方法发回收到的数据
const xmlSendData = require('../../../tools/sendMsg')(jsonData.FromUserName[0], jsonData.ToUserName[0], response.data)
res.end(xmlSendData)
})
} else
//其余消息继续转到下一个中间件处理
next()
}
})
module.exports = dailyVerseMW
- 404页面处理
微信服务器确保外部用户无法非正常的访问,只能通过从微信客户端进行访问。所以当不是微信客户端的请求一律不予支持。
//errorHander.js
module.exports = (req,res)=> {
res.writeHead(404, { 'content-type': 'text/html' })
res.end(`<div style="
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100vh;
">
<h1>404 NOT FOUND!!!</h1>
<a href="https://ivanccc.com">
<h4>back to my homepage<h4><a>
<p>Created By: ivan chen</p>
</div>`)}
效果展示
- 浏览器访问'/wx'
- 浏览器访问其他路径
- 微信端还是能正常访问
之后的想法
会话的保存能够使得服务器有初期AI的能力,引入数据库是我下一步的所要做的。在node上操作我习惯用MongoDB这种非关系型数据库,因为mongoose包很方便对mongoDB进行CURD操作,大家拭目以待,感谢阅读,如有想法欢迎交流,感谢!!!
下一篇: 微信公众号 | 数据的存储 (上)