Skip to content
Permalink
Branch: master
Find file 复制路径
Find file 复制路径
19 contributors

Users who have contributed to this file

@tj @Pana @jonathanong @ZYSzys @ztanner @wachunei @jancarloviray @stojanovic @Equim-chan @robinpokorny @m-a-r-c-e-l-i-n-o @gaomd @frankxin @t3chnoboy @dead-horse @tryzniak @designgrill @qingmingsang @rosald
246行(185坑) 7.01 KB

Guide

本指南涵盖与API不直接相关的Koa主题,例如编写中间件的最佳实践和应用程序结构建议. 在这些示例中,我们使用异步函数作为中间件-您也可以使用commonFunction或generatorFunction,它们会有所不同.

Table of Contents

Writing Middleware

Koa中间件是简单的函数,它们返回带签名的MiddlewareFunction (ctx,下一个). 运行中间件时,它必须手动调用next()才能运行"下游"中间件.

例如,如果您想通过添加X-Response-Time标头字段来跟踪请求通过Koa传播所花费X-Response-Time则中间件将如下所示:

async function responseTime(ctx, next) {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  ctx.set('X-Response-Time', `${ms}ms`);
}

app.use(responseTime);

如果您是前端开发人员,则可以在next();之前考虑任何代码next(); 作为"捕获"阶段,而之后的任何代码都是"冒泡"阶段. 这个粗略的gif说明了异步函数如何使我们能够正确地利用堆栈流来实现请求和响应流:

Koa middleware

  1. 创建日期以跟踪响应时间
  2. 等待控制到下一个中​​间件
  3. 创建另一个日期以跟踪持续时间
  4. 等待控制到下一个中​​间件
  5. 将响应主体设置为" Hello World"
  6. 计算持续时间
  7. 输出日志行
  8. 计算响应时间
  9. 设置X-Response-Time标头字段
  10. 交给Koa处理回应

接下来,我们将研究创建Koa中间件的最佳实践.

Middleware Best Practices

This section covers middleware authoring best practices, such as middleware accepting options, named middleware for debugging, among others.

Middleware options

创建公共中间件时,遵循将中间件包装在接受选项的函数中的约定很有用,该函数允许用户扩展功能. 即使您的中间件不接受任何选项,这也是使事情保持一致的一个好主意.

在这里,我们精心设计的logger中间件接受用于自定义的format字符串,并返回中间件本身:

function logger(format) {
  format = format || ':method ":url"';

  return async function (ctx, next) {
    const str = format
      .replace(':method', ctx.method)
      .replace(':url', ctx.url);

    console.log(str);

    await next();
  };
}

app.use(logger());
app.use(logger(':method :url'));

Named middleware

命名中间件是可选的,但是在调试时分配名称很有用.

function logger(format) {
  return async function logger(ctx, next) {

  };
}

Combining multiple middleware with koa-compose

有时,您想将多个中间件"组合"为一个中间件,以方便重用或导出. 您可以使用koa-compose

const compose = require('koa-compose');

async function random(ctx, next) {
  if ('/random' == ctx.path) {
    ctx.body = Math.floor(Math.random() * 10);
  } else {
    await next();
  }
};

async function backwards(ctx, next) {
  if ('/backwards' == ctx.path) {
    ctx.body = 'sdrawkcab';
  } else {
    await next();
  }
}

async function pi(ctx, next) {
  if ('/pi' == ctx.path) {
    ctx.body = String(Math.PI);
  } else {
    await next();
  }
}

const all = compose([random, backwards, pi]);

app.use(all);

Response Middleware

决定响应请求并希望绕过下游中间件的中间件可以简单地省略next() . 通常,这将在路由中间件中进行,但是任何人都可以执行. 例如,以下内容将以"两个"响​​应,但是所有三个都将执行,从而为下游的"三个"中间件提供了操纵响应的机会.

app.use(async function (ctx, next) {
  console.log('>> one');
  await next();
  console.log('<< one');
});

app.use(async function (ctx, next) {
  console.log('>> two');
  ctx.body = 'two';
  await next();
  console.log('<< two');
});

app.use(async function (ctx, next) {
  console.log('>> three');
  await next();
  console.log('<< three');
});

以下配置在第二个中间件中省略了next() ,并且仍将以" two"响应,但是将忽略第三个(和任何其他下游中间件):

app.use(async function (ctx, next) {
  console.log('>> one');
  await next();
  console.log('<< one');
});

app.use(async function (ctx, next) {
  console.log('>> two');
  ctx.body = 'two';
  console.log('<< two');
});

app.use(async function (ctx, next) {
  console.log('>> three');
  await next();
  console.log('<< three');
});

当最远的下游中间件执行next(); ,它确实具有noop功能,可以使中间件在堆栈中的任何位置正确组成.

Async operations

异步功能和Promise构成了Koa的基础,使您可以编写非阻塞顺序代码. 例如,此中间件从./docs读取文件名,然后在将正文分配给联合结果之前并行读取每个markdown文件的内容.

const fs = require('mz/fs');

app.use(async function (ctx, next) {
  const paths = await fs.readdir('docs');
  const files = await Promise.all(paths.map(path => fs.readFile(`docs/${path}`, 'utf8')));

  ctx.type = 'markdown';
  ctx.body = files.join('');
});

Debugging Koa

Koa及其构建的许多库都支持来自debugDEBUG环境变量,该变量提供了简单的条件日志记录.

例如,要查看所有特定于Koa的调试信息,只需传递DEBUG=koa* ,启动后,您将看到所用中间件的列表.

$ DEBUG=koa* node --harmony examples/simple
  koa:application use responseTime +0ms
  koa:application use logger +4ms
  koa:application use contentLength +0ms
  koa:application use notfound +0ms
  koa:application use response +0ms
  koa:application listen +0ms

由于JavaScript不允许在运行时定义函数名称,因此您也可以将中间件的名称设置为._name . 当您无法控制中间件的名称时,这很有用. 例如:

const path = require('path');
const serve = require('koa-static');

const publicFiles = serve(path.join(__dirname, 'public'));
publicFiles._name = 'static /public';

app.use(publicFiles);

现在,您将不仅看到调试时看到的" serv",还可以看到:

  koa:application use static /public +0ms
您目前无法执行该操作.

by  ICOPY.SITE