koa2快速入门及项目搭建,全局数据拦截

1,276 阅读4分钟

背景:

1、expres express简易的基于nodejs搭建的一个web容器,它基于ES5的语法,要实现异步代码,只能通过回调的形式来实行,但是如果异步嵌套的层次过大,就会导致代码非常难看 如下:

const express = require('express')
const app = express()
app.get('/', function(req, res) {
  res.send('Hello world')
})

app.listen(3000, function() {
   console.log('express is listening is 3000')
})

2、koa1.0 随着新版node.js开始支持ES6,express团队又基于generator重新编写了新一代的web框架koa,和express相比,koa1.0使用generator实现异步,代码看起来同步

var koa = require('koa');
var app = koa()
app.use('/', function* () {
  yield fn();
  var data = yield fn2()
  this.body = data
})

app.listen(3000)

但是这样写有个问题就是,generator的本意并不是异步,Promise才是为异步设计的,但是promise 的写法,我们就要一直.then().then()想想就可怕~~

3、koa2.0的问世是来至于es7提案的async和await,async-await解决了generator 的回调地狱问题

import Koa from 'koa'
const app = new Koa()

app.use(async (ctx, next) => {
  await next()
  let data = await someFn()
  ctx.response.type = 'text/plain'
  ctx.response.body = data
})

koa设计就是洋葱模型,先进后出,一层一层的中间件,可以自行定义,实现方法

话不多说,我们现在开始来搭建我们的koa2吧

项目初始化:

npm ini
npm install koa --save
// 基于koa-generator创建项目
npm install koa-generator -g
koa2 my-first-koa

接下来我们把项目的目录结构调整一下

---controller 专门处理业务的控制器
---error      专门处理报错的处理
------ApiError.js  报错提示方法
------ApiErrorNames.js 报错提示文案配置
------index.js     导出报错方法
---middleware 项目中间件
---plugins    项目第三方依赖,配置文件等
---routers    路由文件
---utils      工具方法
---app.js     主文件
---index.js   入口文件
---package.json 项目配置

为方便使用es6语法,import等方法,我们在执行安装以下2个安装包

npm install babel-register --save
npm install babel-polyfill --save

接下来调整我们的项目文件配置,

首先将index.js文件修改成如下

require('babel-register')
require('babel-polyfill')
//set app
const app = require('./app')

module.exports = app

将bin下的www修改如下

// 原先:
var app = require('../app');
// 修改为:
var app = require('../index');

app.js文件如下

import Koa from 'koa' // 进入koa模块
import json from 'koa-json' // 引入json模块解析
import onerror from 'koa-onerror' // 引入报错
import bodyparser from 'koa-bodyparser' // 请求数据解析

// 引入token校验
import tokenVerify from './middleware/tokenVerify'
// 引入返回响应体公共处理模块
import responseFilter from './middleware/responseFilter'

onerror(app)
app.use(bodyparser())
app.use(json())
app.use(tokenVerify)
app.use(responseFilter())

responseFilter方法的实现

// 导入到处模块
import ApiError from '../error/ApiError'

module.exports = function() {
  return async function(ctx, next) {
    try {
      await next();
      responseFormatter(ctx)
    } catch (error) {
      // 这一块主要处理,在执行数据查询的时候,抛出异常进行全局拦截
      if (error instanceof ApiError) {
        ctx.status = 200;
        ctx.body = {
          code: error.code,
          message: error.message
        }
      }
    }
  }
}

const responseFormatter = ctx => {
  // 这里是对返回来的数据库数据进行统一的数据格式
  if (ctx.body) {
    ctx.body = {
      code: 200,
      message: '',
      data: ctx.body
    }
  }
}

ApiError方法实现如下

import ApiErrorNames from './ApiErrorNames'

function ApiError(names) {
  Error.call(this)
  
  let errorInfo = ApiErrorNames.getErrorInfo(names)
  this.code = errorInfo.code
  this.message = errorInfo.message
}

ApiError.prototype = Object.create(Error.prototype)

export default ApiError

ApiErrorNames文件如下配置
const ApiErrorNames = {
  InvalidToken: { code: 401, message: 'token无效' },
  InvalidUser: { code: 1001, message: '无效的用户' }
}

ApiErrorNames.getErrorInfo = (errorInfo) => {
  if (!errorInfo) {
    errorInfo = ApiErrorNames.UnknownError
  }
  return errorInfo
}

export default ApiErrorNames

接下来我们实现一个login路由,将我们上述的文件联动起来 在controller下新建userController.js

在routers下新增user.js 并在app.js中,引入user路由

// app.js引入
import users from './routes/users'

// 注册users路由
app.use(users.routes(), users.allowedMethods())

routes/user.js代码实现如下:

import UserController from "../controller/userController" // 导入用户控制器
const Router = require('koa-router') // 导入koa路由

// 设置路由前缀名,如果路由过于多的话,这个方法会十分有效
const router = new Router({
  prefix: '/user'
});

router.post('/login', UserController.login)

module.exports = router

controller/userController.js代码实现如下

import {
  ApiError,
  ApiErrorNames
} from '../error'

class UserController {
  static async login(ctx) {
    // 获取用户提交过来信息
    let {
      name,password
    } = ctx.request.body
    
    // ...查询数据库一系列操作
    // 用户不存在
    throw new ApiError(ApiErrorNames.InvalidUser)
    
    // 用户存在
    ctx.body = data
  }
}

export default UserController;

接下来通过node启动我们的服务

npm run start

通过api接口或者前端页面进行接口请求

post http://localhost:端口号/user/login

这样就可以愉快的开发我们nodejs服务层的api接口了

我是godlike,每周一篇小技巧,一起快速入坑,希望能在前端道路上,和你努力,一起共勉!