Skip to content

koa知识梳理 #23

@Clearives

Description

@Clearives

koa知识梳理

实现 Async 方法

要在 node < 7.6 版本的 Koa 中使用 async 方法, 我们推荐使用 babel's require hook.

require('babel-register');
// 应用的其余 require 需要被放到 hook 后面
const app = require('./app');

要解析和编译 async 方法, 你至少应该有 transform-async-to-generator 或 transform-async-to-module-method 插件.

实现 import & export default

使用babel-plugin-add-module-exports

"plugins": [
  "add-module-exports"
]

koa中间件级联

通过一系列功能直接传递控制,直到一个返回,Koa 调用“下游”,然后控制流回“上游”。

const Koa = require('koa');
const app = new Koa();

// logger

app.use(async (ctx, next) => {
  console.log(1)
  await next();
  console.log(5)
  const rt = ctx.response.get('X-Response-Time');
  console.log(`${ctx.method} ${ctx.url} - ${rt}`);
});

// x-response-time

app.use(async (ctx, next) => {
  console.log(2)
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  console.log(4)
  ctx.set('X-Response-Time', `${ms}ms`);
});

// response

app.use(async ctx => {
  console.log(3)
  ctx.body = 'Hello World';
});

app.listen(3000);

上面例子打印的顺序是12345。

语法糖 app.listen(...)

const http = require('http');
const Koa = require('koa');
const app = new Koa();
http.createServer(app.callback()).listen(3000);

app.use & 中间件(middleware)

export default async (ctx, next) => {
  const start = new Date();
  await next();
  const ms = new Date() - start;
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
}

这是一个logger中间件,app.use()用来加载中间件,每个中间件默认接受两个参数,第一个参数是 Context 对象,第二个参数是next函数。只要调用next函数,就可以把执行权转交给下一个中间件。
这里我们再回过头看上面的输出12345会引出中间件栈的说法,此处参考阮一峰老师的文章。

多个中间件会形成一个栈结构(middle stack),以"先进后出"(first-in-last-out)的顺序执行。

  1. 最外层的中间件首先执行。
  2. 调用next函数,把执行权交给下一个中间件。
  3. ...
  4. 最内层的中间件最后执行。
  5. 执行结束后,把执行权交回上一层的中间件。
  6. ...
  7. 最外层的中间件收回执行权之后,执行next函数后面的代码。

中间件包括同步和异步,异步的必须加上async await

错误处理

如果代码运行过程中发生错误,我们需要把错误信息返回给用户。HTTP 协定约定这时要返回500状态码。Koa 提供了ctx.throw()方法,用来抛出错误,ctx.throw(500)就是抛出500错误。

const code2Token = async (ctx, next) => {
  const request = ctx.request.body;
  const code = request.code;
  let res = await axios.get(`${wx.loginUrl}?appid=${wx.appId}&secret=${wx.appSecret}&js_code=${code}&grant_type=authorization_code`)
  if (res.data.errcode && res.data.errcode !== 0) {
    ctx.throw(412, res.data.errmsg) // 抛异常
  }

  let user = await WxUserService.getUserByOpenid(res.data.openid)

  if (!user) {
    user = await WxUserService.createUserByOpenid(res.data.openid)
  }

  let token = jwtUtil.sign({_id: user.openid})
  ctx.body = Resp({
    data: {
      openid: user.openid,
      token
    }
  })
};

涉及到的node模块相关内容

path

node-path.png

path.dirname(path)

该方法返回 path 的目录名

path.join([...paths])

该方法使用平台特定的分隔符作为定界符将所有给定的 path 片段连接在一起,然后规范化生成的路径,零长度的 path 片段会被忽略。 如果连接的路径字符串是零长度的字符串,则返回 '.',表示当前工作目录。

path.resolve([...paths])

该方法将路径或路径片段的序列解析为绝对路径。

basename(文件名)、extname(扩展名)、dirname(文件所在文件夹名称)

http

http.createServer

http模块主要用于搭建HTTP服务。使用Node搭建HTTP服务器非常简单。

const http = require('http');
const PORT = 3001;
const server = http.createServer((req, res) => {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.write("Hello World");
  res.end();
})
server.listen(PORT, function() {
  console.log(`the server is started at port ${PORT}`)
})

events

const Emitter = require('events');
/** module.exports = class Application extends Emitter {...} 导出了koa类 **/ 
/** application.js 继承了 Emitter,所有它也包含了异步事件的处理能力,后面可以看到koa的错误处理会使用到Emitter提供的事件模型方法。 **/

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions