此系列文章的应用示例已发布于 GitHub: koa-docs-Zh-CN. 能够 Fork 帮助改进或 Star 关注更新. 欢迎 Star.前端
本指南涵盖的 Koa 主题不与 API 直接相关,例如编写中间件的最佳作法和应用程序结构建议。在这些例子中,咱们使用 async 函数做为中间件 - 您也可使用 commonFunction 或generatorFunction,这将些所不一样。node
Koa 中间件是简单的函数,它返回一个带有签名 (ctx, next) 的MiddlewareFunction
。当中间件运行时,它必须手动调用 next()
来运行 “下游” 中间件。git
例如,若是你想要跟踪经过添加 X-Response-Time
头字段经过 Koa 传播请求须要多长时间,则中间件将以下所示:github
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();
以前的任意代码视为“捕获”阶段,这个简易的 gif 说明了 async 函数如何使咱们可以恰当地利用堆栈流来实现请求和响应流:promise
X-Response-Time
头字段接下来,咱们将介绍建立 Koa 中间件的最佳作法。markdown
本节介绍中间件创做最佳实践,例如中间件接受参数,命名中间件进行调试等等。app
当建立公共中间件时,将中间件包装在接受参数的函数中,遵循这个约定是有用的,容许用户扩展功能。即便您的中间件 不 接受任何参数,这仍然是保持统一的好方法。dom
这里咱们设计的 logger
中间件接受一个 format
自定义字符串,并返回中间件自己:koa
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'));
命名中间件是可选的,可是在调试中分配名称颇有用。异步
function logger(format) { return async function logger(ctx, next) { }; }
有时您想要将多个中间件 “组合” 成一个单一的中间件,便于重用或导出。你可使用 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);
中间件决定响应请求,并但愿绕过下游中间件能够简单地省略 next()
。一般这将在路由中间件中,但这也能够任意执行。例如,如下内容将以 “two” 进行响应,可是全部三个都将被执行,从而使下游的 “three” 中间件有机会操纵响应。
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 方法和 promise 来自 Koa 的底层,可让你编写非阻塞序列代码。例如,这个中间件从 ./docs
读取文件名,而后在将给 body 指定合并结果以前并行读取每一个 markdown 文件的内容。
const fs = require('fs-promise'); 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(''); });
Koa 以及许多构建库,支持来自 debug 的 DEBUG 环境变量,它提供简单的条件记录。
例如,要查看全部 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);
如今,在调试时不仅会看到 “serve”,你也会看到:
Now, instead of just seeing "serve" when debugging, you will see:
koa:application use static /public +0ms
若是这篇文章对您有帮助, 感谢 下方点赞 或 Star GitHub: koa-docs-Zh-CN 支持, 谢谢.