专栏首页小程序解决方案的专栏Wafer2 Node.js QuickStart 架构分析
原创

Wafer2 Node.js QuickStart 架构分析

与 Wafer1 的 Node.js Demo 采用 Express 不同,Wafer2 的 Node.js QuickStart 采用了 Koa.js 框架编写,Koa 将整个请求过程看做全异步的操作,使用 Node.js 7.6 开始支持的 async/await 语法,大大简化了整个应用开发的繁琐性,能让我们写出更加好看的异步代码。关于 async/await,这里不过多的介绍,有兴趣的同学可以查看阮一峰的 async/await 教程

Koa 中间件 - 洋葱模型

Koa 的中间件模式和 Express 不同,Express 的中间件是流式串行结构,当一个中间件调用了 next 函数,逻辑就再也不会回到这个中间件中,这种模型在一些情况下会使得很多我们想要实现的功能变得复杂,比如请求时间计算,我们不得不将请求的开始时间写进 request 对象,而对于全局错误的捕获,我们也只能监听 uncaughtException 事件,这样导致我们的应用架构变得不够清晰。

而 Koa 的洋葱模型巧妙的解决了这个文件,它将所有的中间件(或者处理业务的函数)看成是异步的,next 函数则返回一个 Promise 对象,每一个中间件会包裹住下一个中间件,如同洋葱一样,请求(ctx 对象)从最外层进到最里层,又从最里层再流出来,简化了我们整个应用设计的难度。

response 中间件

同大部分 Node.js 程序一样,应用的入口是 app.js,应用的最开始会先引入一个 response 中间件:

app.use(response)

这个中间件用来处理整个应用的异常捕获和请求响应结束之后的响应数据封装。

打开 middlewares/response.js 文件,可以看到如下代码:

const debug = require('debug')('koa-weapp-demo')

/**
 * 响应处理模块
 */
module.exports = async function (ctx, next) {
    try {
        // 调用下一个 middleware
        await next()

        // 处理响应结果
        // 如果直接写入在 body 中,则不作处理
        // 如果写在 ctx.body 为空,则使用 state 作为响应
        ctx.body = ctx.body ? ctx.body : {
            code: ctx.state.code !== undefined ? ctx.state.code : 0,
            data: ctx.state.data !== undefined ? ctx.state.data : {}
        }
    } catch (e) {
        // catch 住全局的错误信息
        debug('Catch Error: %o', e)

        // 设置状态码为 200 - 服务端错误
        ctx.status = 200

        // 输出详细的错误信息
        ctx.body = {
            code: -1,
            error: e && e.message ? e.message : e.toString()
        }
    }
}

response 中间件对全局做了一个 try...catch 操作,将 next() 的调用错误给 catch 住,防止请求过程中的某一个错误导致整个 Node 程序退出。同时,在请求结束之后,会从 ctx.state 取出 data 和 code 两个字段,封装进 ctx.body 中,ctx.body 就是整个引用最后返回给前端的数据,Koa 会对 ctx.body 进行 JSON 序列化,并在 http header 上加上响应的类型头。

路由

QuickStart 使用的是 koa-router 来处理路由映射,打开 routes/index.js 可以看到,本文件中统一处理所有的路由。其中与用户登录授权有关的两个路由与别的不同,分别使用了 SDK 导出的 authorizationMiddleware 和 validationMiddleware 中间件。

// --- 登录与授权 Demo --- //

// 登录接口
router.get('/login', authorizationMiddleware, controllers.login)

// 用户信息接口(可以用来验证登录态
router.get('/user', validationMiddleware, controllers.user)

只有通过了这两个中间件的处理,才会执行后面相关的 controllers。

控制器映射

QuickStart 中还有一个值得分享的就是控制器映射,打开 controllers/index.js 文件,可以看到如下代码:

const _ = require('lodash')
const fs = require('fs')
const path = require('path')

/**
 * 映射 d 文件夹下的文件为模块
 */
const mapDir = d => {
    const tree = {}

    // 获得当前文件夹下的所有的文件夹和文件
    const [dirs, files] = _(fs.readdirSync(d)).partition(p => fs.statSync(path.join(d, p)).isDirectory())

    // 映射文件夹
    dirs.forEach(dir => {
        tree[dir] = mapDir(path.join(d, dir))
    })

    // 映射文件
    files.forEach(file => {
        if (path.extname(file) === '.js') {
            tree[path.basename(file, '.js')] = require(path.join(d, file))
        }
    })

    return tree
}

// 默认导出当前文件夹下的映射
module.exports = mapDir(path.join(__dirname))

controllers/index.js 是所有控制器默认导出的文件,他遍历了 controllers 文件夹下的所有文件和文件夹,并生成一个对象结构。

例如,如下的文件夹结构:

── controllers
   ├── user.js
       └── login.js
   └── upload.js

会被映射为如下的 JavaScript 对象:

{
    user: {
        login: require('./user/login.js')
    },
    upload: require('./upload.js')
}

这样,我们只需引入 controllers/index.js 就可以引入所有的 controllers,创建一个新的文件夹和文件,也可以马上通过 controllers/index.js 来访问到,无需单独 require,让整个应用更加的清晰。

结语

这次关于 Node.js 版本 QuickStart 的代码就分享到这里,欢迎大家使用腾讯云微信小程序解决方案。如果有什么更好的意见或者建议,可以在评论中提出来,一起讨论一下。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 自己部署 Node.js 版本的 Wafer2 Demo

    自行部署适用于想将腾讯云 Wafer SDK 和 Demo 部署在自己的服务器上以获得更高的灵活性和操纵权限的用户。部署过程需要从 0 开始搭建线上环境,需要有...

    Jason
  • 3 元购买 Wafer1 指南

    进入微信公众平台,点击右上角的【立即注册】,按照流程注册小程序账号。

    Jason
  • 基于腾讯云智能语音的实时语音识别微信小程序的开发

    微信小程序的基础库升级到了 1.6.0 之后,提供了许多新的 API,其中新增了录音管理的 API,不同于以前只有 wx.startRecord 和 wx.st...

    Jason
  • 怎么学JavaScript?

    鉴于时不时,有同学私信问我(老姚,下同)怎么学前端的问题。这里统一回复一下,如下次再遇到问我此问题同学,就直接把本文链接地址发给你了。

    Nealyang
  • 统一回复《怎么学JavaScript?》

    于时不时,有同学私信问我怎么学前端的问题。 这里统一回复一下,如下次再遇到问我此问题同学,就直接把本文链接地址发给你了。 首先说句题外话。关于有人管我叫大神的...

    用户1667431
  • 浅谈如何学习JavaScript?

    首先说句题外话。关于有人管我叫大神的事情。个人感觉这跟你买东西时,人家管你叫帅哥一样,你答应与否都无妨。

    前端迷
  • Laravel源码解析之中间件

    中间件(Middleware)在Laravel中起着过滤进入应用的HTTP请求对象(Request)和完善离开应用的HTTP响应对象(Reponse)的作用, ...

    KevinYan
  • 微服务与Node.js为什么会广受喜爱?

    大多数项目开始时都是为了解决某一问题,比较简单,后来逐渐发展,就变得越来越大,形成一个很大的单体结构,所有的新功能都会向这个单体中添加,就像滚雪球,越来越大 ...

    dys
  • 3. 源码分析---SOFARPC客户端服务调用

    所以当我们用BoltClientProxyInvoker#invoke的时候实际上是调用了父类的invoke方法 ClientProxyInvoker#inv...

    luozhiyun

扫码关注云+社区

领取腾讯云代金券