Koa middlewares are simple function which return a GeneratorFunction, and accept another (middleware). When the middleware is run by an “upstream” middleware, it must manually yield to the “downstream” middleware.

For example if you wanted to track how long it takes for a request to propagate through Koa by adding an x-Response-Time header field the middleware would look like the following:

function *responseTime(next){
  var start = new Date;
  yield next;
  var ms = new Date - start;
  this.set("X-Response-Time", ms+"ms");
}
app.use(responseTime);
`</pre>

Here is another way to write the same thing, inline:

<pre>`app.use(function *(next){
  var start = new Date;
  yield next;
  var ms = new Date - start;
  this.set("X-Response-Time", ms+"ms");
});
`</pre>

### 中间件最佳实践

Imcluding Middleware accepting options, named middleware for debugging, among others

#### 中间件选项

When creating public middleware it's useful to conform to the convention of wrapping the middleware in a function that accepts options, allowing users to extend functionality. Even if your middleware accepts no options, this is still a good idea to keep things uniform.

Here our contrived `logger` middleware accepts a `format` string for customization, and returns the middleware itself:

<pre>`function logger(format){
  format = format || ":method\":url\"";
  return function*(next){
    var str = format.replace(":method", this.method).replace(":url", this.url);
    console.log(str);
    yield next;
  }
}
`</pre>

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

<pre>`
### 命名中间件
Naming middlewares is optional, however it's useful for debugging purpose to assign a name
`</pre>

function logger(format){
  return function *logger(next){
    // ...
  }
}

<pre>`### 结合多个中间件
Sometimes you want to "compose" multiple middleware into a single middleware for easy re-use or exporting. To do so, you may chain them together with `.call(this, next)`, then return another function that yields the chain

function _random(next) {
if (‘/random’ == this.path) {
this.body = Math.floor(Math.random()_10);
} else {
yield next;
}
};

function *backwards(next) {
if (‘/backwards’ == this.path) {
this.body = ‘sdrawkcab’;
} else {
yield next;
}
}

function *pi(next) {
if (‘/pi’ == this.path) {
this.body = String(Math.PI);
} else {
yield next;
}
}

function *all(next) {
yield random.call(this, backwards.call(this, pi.call(this, next)));
}

app.use(all);

1