Koa

Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。

正因为 Koa 没有捆绑任何中间件,所以我们在开发应用的时候一定要注意自己开发,或者找 Koa 对应的中间件,并且还要注意对应的版本。

在 Express 中我们有 express-generator ,而 Koa 官方并没有为我们提供官方的快速构建框架,但是开发者开源了非常多的优秀框架例如:

关于不同框架的使用方法不一样,在此就不一一举例,大家可以自行查阅其框架文档。Koa 主要的优势是 ES6 + 轻量定制化,以下我们就用 Koa 快速开发一个查询接口。

  1. 初始化项目
cd ~/Desktop && mkdir koaApp && cd koaApp
npm init
  1. 下载相关依赖
  • koa
  • koa-router
  • axios
npm install koa koa-router axios --save
  1. 创建入口主文件 app.js
touch app.js

app.js

// 引入 koa 框架
const Koa = require('koa');
// 引入 路由
const router = require('./routes');
// 实例化应用
const app = new Koa();

// 使用路由,监听3000 端口
app
  .use(router.routes())
  .use(router.allowedMethods())
  .listen(3000)
  1. 新建路由 routes/index.js

routes/index.js

const router = require('koa-router')({
  prefix: '/'
})

const indexController = require('../controllers/index.js')

router.get('/', indexController.indexRender)

module.exports = router
  1. 创建首页控制器 controllers/index.js

controllers/index.js

const indexController = {
  indexRender: async (ctx, next) => {
    ctx.body = 'Hello Koa!'
  } 
}

module.exports = indexController;
  1. 启动代码,打开http://localhost:3000/,你就可以看到,Hello Koa!
nodemon app.js

第三方请求

  1. 新建豆瓣数据模型 models/douban.js

models/douban.js

const axios = require('axios');
const ISBNAPI = 'https://api.douban.com/v2/book/isbn/';
// const mock_id = '9787121317989';

const douban = {
  isbn:function(isbn){
    return new Promise((resolve,reject) => {
      axios.get(ISBNAPI + isbn).then( res => {
        resolve(res.data)
      }).catch( err => {
        reject(err.response.data)
      })
    })
  }
}

module.exports = douban;
  1. 新建书目控制器 controllers/book.js

controllers/book.js

const doubanModel = require('./../models/douban');

const book = {
  info:async function(ctx, next){

    const ISBN = ctx.query.isbn;
    if(!ISBN){
      ctx.body = { code: 0,msg: 'isbn empty!'}
      return
    }

    try{
      const data = await doubanModel.isbn(ISBN);
      ctx.body = { code: 200, data: data }
    }catch(err) {
      ctx.body = err
    }
  }
}

module.exports = book;
  1. 添加接口 routes/index.js

routes/index.js

const router = require('koa-router')({
  prefix: '/'
})

const indexControllers = require('../controllers/index.js')
const bookController = require('./../controllers/book');

router.get('/', indexControllers.indexRender)
router.get('api/isbn', bookController.info);

module.exports = router
  1. 请求测试 http://localhost:3000/api/isbn?isbn=9787121317989

CORS中间件

Koa的机制和 Express 不一样的地方是,Express是一个流式,从上到下。而 Koa 的机制是洋葱形,中间件会有两次执行的时机。以下我们将创建全局中间件和局部的中间件,全局中间件有点类似 Express 的 filter作用,而局部中间件和 Express 的中间件相识,但是在 next 的时候需要添加 await。

  1. 创建输出中间件 middlewares/response.js

middlewares/response.js

const debug = require('debug')('koa-app')

/**
 * 响应处理模块
 */
module.exports = async function (ctx, next) {
  try {
    await next()

    // 处理响应结果
    // 如果直接写入在 body 中,则不作处理
    // 如果写在 ctx.body 为空,则使用 state 作为响应
    // ctx.body = {
    //     code:0,
    //     data:{}
    // }
    console.log(ctx.url)
    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()
    }
  }
}
  1. 创建CORS中间件 middlewares/cors.js

middlewares/cors.js

const cors = {
    allowAll: async function(ctx, next){
        ctx.set('Acess-Control-Allow-Origin','*');
        ctx.set('Access-Control-Allow-Origin', '*');
        ctx.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
        ctx.set('Access-Control-Allow-Credentials', 'true');
        await next()
    }
}

module.exports = cors;
  1. 应用全局response中间件 app.js

app.js

const Koa = require('koa');
const router = require('./routes');
const app = new Koa();
const response = require('./middlewares/response');

app
  .use(response)
  .use(router.routes())
  .use(router.allowedMethods())
  .listen(3000)
  1. 引用CORS局部中间件 routes/index.js

routes/index.js

const router = require('koa-router')({
  prefix: '/'
})

const indexControllers = require('../controllers/index.js');
const bookController = require('./../controllers/book');
const cors = require('./../middlewares/cors');

router.get('/', indexControllers.indexRender);
router.get('api/isbn', cors.allowAll,bookController.info);

module.exports = router