Node.js向け次世代Webフレームワーク

はじめに

Koaは、Expressの開発チームによって設計された新しいWebフレームワークです。WebアプリケーションとAPIのための、より小さく、より表現力豊かで、より堅牢な基盤を目指しています。非同期関数を利用することで、コールバックを排除し、エラー処理を大幅に改善できます。Koaはコアにミドルウェアをバンドルしておらず、サーバーの記述を迅速かつ快適にするためのエレガントなメソッド群を提供します。

インストール

KoaはES2015と非同期関数サポートのために、**Node v12**以降が必要です。

お好みのバージョンマネージャーを使用して、サポートされているバージョンのNodeを簡単にインストールできます。

$ nvm install 7
$ npm i koa
$ node my-koa-app.js

アプリケーション

Koaアプリケーションは、ミドルウェア関数の配列を含むオブジェクトです。これらの関数は、リクエスト時にスタックのような方法で合成され、実行されます。Koaは、RubyのRack、Connectなど、これまで遭遇した可能性のある他の多くのミドルウェアシステムと似ていますが、低レベルのミドルウェア層に高レベルの「糖衣構文」を提供するという重要な設計上の決定が行われました。これにより、相互運用性と堅牢性が向上し、ミドルウェアの記述がより快適になります。

これには、コンテンツネゴシエーション、キャッシュの鮮度、プロキシサポート、リダイレクトなど、一般的なタスクのためのメソッドが含まれます。Koaは便利なメソッドをかなり多く提供していますが、ミドルウェアはバンドルされていないため、フットプリントは小さくなっています。

お約束のHello Worldアプリケーション

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

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

app.listen(3000);

カスケード

Koaミドルウェアは、同様のツールで慣れているように、より従来の方法でカスケードします。これは、以前はNodeのコールバックの使用ではユーザーフレンドリーにするのが困難でした。しかし、非同期関数を使用することで、「真の」ミドルウェアを実現できます。Connectの実装は、関数のシリーズを通して制御を渡すだけで、1つが返されるまで続けますが、Koaは「ダウンストリーム」を呼び出し、その後制御が「アップストリーム」に戻ります。

次の例では「Hello World」を返しますが、最初にリクエストはx-response-timeloggingミドルウェアを通過してリクエスト開始時刻をマークし、レスポンスミドルウェアを通して制御を譲ります。ミドルウェアがnext()を呼び出すと、関数は中断され、定義されている次のミドルウェアに制御が渡されます。ダウンストリームに実行するミドルウェアがなくなると、スタックはアンワインドされ、各ミドルウェアは再開されてアップストリームの動作を実行します。

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

// logger

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

// x-response-time

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

// response

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

app.listen(3000);

設定

アプリケーション設定はappインスタンスのプロパティです。現在、以下がサポートされています。

app.listen(...)

Koaアプリケーションは、HTTPサーバーの1対1の表現ではありません。1つ以上のKoaアプリケーションをマウントして、単一のHTTPサーバーを持つより大きなアプリケーションを形成できます。

与えられた引数をServer#listen()に渡してHTTPサーバーを作成および返します。これらの引数はnodejs.orgで説明されています。以下は、ポート3000にバインドされた役に立たないKoaアプリケーションです。

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

app.listen(...)メソッドは、単に以下の糖衣構文です。

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

つまり、同じアプリケーションをHTTPとHTTPSの両方、または複数のアドレスで起動できます。

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

app.callback()

http.createServer()メソッドに適したコールバック関数を返し、リクエストを処理します。このコールバック関数を使用して、KoaアプリをConnect/Expressアプリにマウントすることもできます。

app.use(function)

このアプリケーションに指定されたミドルウェア関数を追加します。app.use()thisを返し、チェーン可能です。

app.use(someMiddleware)
app.use(someOtherMiddleware)
app.listen(3000)

これは以下と同じです。

app.use(someMiddleware)
  .use(someOtherMiddleware)
  .listen(3000)

詳細はMiddlewareを参照してください。

app.keys=

署名付きクッキーキーを設定します。

これらはKeyGripに渡されますが、独自のKeyGripインスタンスを渡すこともできます。たとえば、以下は許容されます。

app.keys = ['OEK5zjaAMPc3L6iK7PyUjCOziUH3rsrMKB9u8H07La1SkfwtuBoDnHaaPCkG5Brg', 'MNKeIebviQnCPo38ufHcSfw3FFv8EtnAe1xE02xkN1wkCV1B2z126U44yk2BQVK7'];
app.keys = new KeyGrip(['OEK5zjaAMPc3L6iK7PyUjCOziUH3rsrMKB9u8H07La1SkfwtuBoDnHaaPCkG5Brg', 'MNKeIebviQnCPo38ufHcSfw3FFv8EtnAe1xE02xkN1wkCV1B2z126U44yk2BQVK7'], 'sha256');

セキュリティ上の理由から、キーが十分な長さでランダムであることを確認してください。

これらのキーはローテーションでき、{ signed: true }オプションでクッキーに署名する際に使用されます。

ctx.cookies.set('name', 'tobi', { signed: true });

app.context

app.contextは、ctxが作成されるプロトタイプです。app.contextを編集することで、ctxに追加のプロパティを追加できます。これは、アプリ全体で使用されるプロパティまたはメソッドをctxに追加するのに役立ち、パフォーマンスの向上(ミドルウェアなし)や簡素化(require()の削減)につながる可能性がありますが、ctxへの依存度が高まるという欠点もあります(アンチパターンと見なされる可能性があります)。

たとえば、データベースへの参照をctxに追加するには

app.context.db = db();

app.use(async ctx => {
  console.log(ctx.db);
});

注記

エラー処理

デフォルトでは、app.silenttrueでない限り、すべてのエラーをstderrに出力します。デフォルトのエラーハンドラーは、err.status404の場合、またはerr.exposetrueの場合にもエラーを出力しません。中央集権化されたログ記録などのカスタムエラー処理ロジックを実行するには、「error」イベントリスナーを追加できます。

app.on('error', err => {
  log.error('server error', err)
});

エラーがreq/resサイクル内にあり、クライアントにレスポンスできない場合、Contextインスタンスも渡されます。

app.on('error', (err, ctx) => {
  log.error('server error', err, ctx)
});

エラーが発生しクライアントにまだレスポンスできる場合(ソケットにデータが書き込まれていない場合)、Koaは適切に500「Internal Server Error」でレスポンスします。どちらの場合も、ログ記録のためにアプリレベルの「error」が発行されます。

コンテキスト

Koaコンテキストは、Nodeのrequestオブジェクトとresponseオブジェクトを単一のオブジェクトにカプセル化し、WebアプリケーションとAPIを作成するための多くの便利なメソッドを提供します。これらの操作はHTTPサーバー開発で非常に頻繁に使用されるため、より高レベルのフレームワークではなく、このレベルに追加されます。これにより、ミドルウェアがこの共通機能を再実装する必要がなくなります。

Contextはリクエストごとに作成され、ミドルウェアではレシーバー、またはctx識別子として参照されます(次のスニペットに示されています)。

app.use(async ctx => {
  ctx; // is the Context
  ctx.request; // is a Koa Request
  ctx.response; // is a Koa Response
});

コンテキストのアクセサーとメソッドの多くは、便宜上、ctx.requestまたはctx.responseの同等のものに対応するだけです。たとえば、ctx.typectx.lengthresponseオブジェクトに対応し、ctx.pathctx.methodrequestに対応します。

API

Context固有のメソッドとアクセサー。

ctx.req

Nodeのrequestオブジェクト。

ctx.res

Nodeのresponseオブジェクト。

Koaのレスポンス処理をバイパスすることは**サポートされていません**。以下のNodeプロパティの使用は避けてください。

ctx.request

KoaのRequestオブジェクト。

ctx.response

KoaのResponseオブジェクト。

ctx.state

ミドルウェアとフロントエンドビューを通して情報を渡すための推奨ネームスペース。

ctx.state.user = await User.find(id);

ctx.app

アプリケーションインスタンスへの参照。

ctx.app.emit

Koaアプリケーションは内部のEventEmitterを拡張します。ctx.app.emitは、最初の引数で定義されたタイプを持つイベントを発行します。各イベントに対して、「リスナー」を接続できます。これは、イベントが発行されたときに呼び出される関数です。詳細はエラー処理のドキュメントを参照してください。

ctx.cookies.get(name, [options])

optionsでクッキーnameを取得します。

Koaはcookiesモジュールを使用し、オプションはそのまま渡されます。

ctx.cookies.set(name, value, [options])

optionsでクッキーnamevalueに設定します。

Koaはcookiesモジュールを使用し、オプションはそのまま渡されます。

ctx.throw([status], [msg], [properties])

.statusプロパティ(デフォルトは500)を持つエラーをスローするヘルパーメソッドで、Koaが適切にレスポンスできるようにします。次の組み合わせが許可されます。

ctx.throw(400);
ctx.throw(400, 'name required');
ctx.throw(400, 'name required', { user: user });

たとえば、ctx.throw(400, 'name required')は以下と同等です。

const err = new Error('name required');
err.status = 400;
err.expose = true;
throw err;

これらはユーザーレベルのエラーであり、err.exposeでフラグが付けられていることに注意してください。つまり、メッセージはクライアントレスポンスに適しています。これは、通常、エラーメッセージの場合には当てはまりません。失敗の詳細を漏らしたくないためです。

必要に応じて、エラーにそのままマージされるpropertiesオブジェクトを渡すことができます。これは、アップストリームのリクエスターに報告されるマシンフレンドリーなエラーを装飾するのに役立ちます。

ctx.throw(401, 'access_denied', { user: user });

Koaはhttp-errorsを使用してエラーを作成します。statusは最初の引数としてのみ渡す必要があります。

ctx.assert(value, [status], [msg], [properties])

!valueの場合に.throw()と同様のエラーをスローするヘルパーメソッド。Nodeのassert()メソッドに似ています。

ctx.assert(ctx.state.user, 401, 'User not found. Please login!');

Koaはhttp-assertをアサーションに使用します。

ctx.respond

Koaの組み込みレスポンス処理をバイパスするには、明示的にctx.respond = false;を設定できます。Koaがレスポンスを処理する代わりに、生のresオブジェクトに書き込む場合は、これを使用します。

これはKoaでは**サポートされていません**。KoaミドルウェアやKoa自体の意図した機能を壊す可能性があります。このプロパティの使用はハックとみなされ、従来のfn(req, res)関数とミドルウェアをKoaで使用したいユーザーのための便宜的なものです。

リクエストのエイリアス

以下のアクセッサとエイリアスはRequestと同等です。

レスポンスのエイリアス

以下のアクセッサとエイリアスはResponseと同等です。

リクエスト

KoaのRequestオブジェクトは、Nodeの標準的なリクエストオブジェクトの上位に構築された抽象化レイヤーであり、日常的なHTTPサーバー開発に役立つ追加機能を提供します。

API

request.header

リクエストヘッダーオブジェクト。これはNodeのheadersフィールド(http.IncomingMessage)と同じです。

request.header=

リクエストヘッダーオブジェクトを設定します。

request.headers

リクエストヘッダーオブジェクト。request.headerのエイリアスです。

request.headers=

リクエストヘッダーオブジェクトを設定します。request.header=のエイリアスです。

request.method

リクエストメソッド。

request.method=

リクエストメソッドを設定します。methodOverride()などのミドルウェアの実装に役立ちます。

request.length

存在する場合、リクエストのContent-Lengthを数値で返し、存在しない場合はundefinedを返します。

request.url

リクエストURLを取得します。

request.url=

リクエストURLを設定します。URLの書き換えに役立ちます。

request.originalUrl

リクエストの元のURLを取得します。

request.origin

URLのオリジン(プロトコルとホストを含む)を取得します。

ctx.request.origin
// => http://example.com

request.href

完全なリクエストURL(プロトコル、ホスト、URLを含む)を取得します。

ctx.request.href;
// => http://example.com/foo/bar?q=1

request.path

リクエストのパス名を取得します。

request.path=

リクエストのパス名を設定し、クエリ文字列が存在する場合は保持します。

request.querystring

?を除いた生のクエリ文字列を取得します。

request.querystring=

生のクエリ文字列を設定します。

?を含む生のクエリ文字列を取得します。

request.search=

生のクエリ文字列を設定します。

request.host

存在する場合、ホスト(ホスト名:ポート)を取得します。app.proxytrueの場合、X-Forwarded-Hostをサポートします。それ以外の場合は、Hostを使用します。

request.hostname

存在する場合、ホスト名を取得します。app.proxytrueの場合、X-Forwarded-Hostをサポートします。それ以外の場合は、Hostを使用します。

ホストがIPv6の場合、KoaはWHATWG URL APIにパース処理を委任します。注意 パフォーマンスに影響する可能性があります。

request.URL

WHATWGでパースされたURLオブジェクトを取得します。

request.type

"charset"などのパラメータを除いたリクエストのContent-Typeを取得します。

const ct = ctx.request.type;
// => "image/png"

request.charset

存在する場合、リクエストのcharsetを返し、存在しない場合はundefinedを返します。

ctx.request.charset;
// => "utf-8"

request.query

パースされたクエリ文字列を取得します。クエリ文字列が存在しない場合は空のオブジェクトを返します。このゲッターはネストされたパースをサポート**しません**。

例:"color=blue&size=small"

{
  color: 'blue',
  size: 'small'
}

request.query=

指定されたオブジェクトにクエリ文字列を設定します。このセッターはネストされたオブジェクトをサポート**しません**。

ctx.query = { next: '/login' };

request.fresh

リクエストキャッシュが「新鮮」であるかどうか(つまり、コンテンツが変更されていないかどうか)を確認します。このメソッドは、If-None-Match / ETagIf-Modified-SinceLast-Modifiedの間のキャッシュネゴシエーション用です。これらのレスポンスヘッダーの1つ以上を設定した後に参照する必要があります。

// freshness check requires status 20x or 304
ctx.status = 200;
ctx.set('ETag', '123');

// cache is ok
if (ctx.fresh) {
  ctx.status = 304;
  return;
}

// cache is stale
// fetch new data
ctx.body = await db.find('something');

request.stale

request.freshの逆です。

request.protocol

リクエストプロトコル("https"または"http")を返します。app.proxytrueの場合、X-Forwarded-Protoをサポートします。

request.secure

ctx.protocol == "https"の略記で、リクエストがTLS経由で行われたかどうかを確認します。

request.ip

リクエストのリモートアドレス。app.proxytrueの場合、X-Forwarded-Forをサポートします。

request.ips

X-Forwarded-Forが存在し、app.proxyが有効になっている場合、これらのIPアドレスの配列がアップストリームからダウンストリームの順序で返されます。無効になっている場合は空の配列が返されます。

例えば、値が"client, proxy1, proxy2"の場合、["client", "proxy1", "proxy2"]という配列を受け取ります。

ほとんどのリバースプロキシ(nginx)はproxy_add_x_forwarded_forを使用してx-forwarded-forを設定しますが、これは特定のセキュリティリスクをもたらします。悪意のある攻撃者は、X-Forwarded-Forリクエストヘッダーを偽造することで、クライアントのIPアドレスを偽造できます。クライアントから送信されたリクエストには、「偽造」のX-Forwarded-Forリクエストヘッダーがあります。リバースプロキシによって転送された後、request.ipsは['forged', 'client', 'proxy1', 'proxy2']になります。

Koaは回避策を2つ提供しています。

リバースプロキシを制御できる場合は、設定を調整することで回避策を回避するか、Koaが提供するapp.proxyIpHeaderを使用してx-forwarded-forの読み取りを回避し、IPアドレスを取得できます。

  const app = new Koa({
    proxy: true,
    proxyIpHeader: 'X-Real-IP',
  });

サーバーの前に存在するリバースプロキシの数を正確に知っている場合は、app.maxIpsCountを設定することで、ユーザーの偽造されたリクエストヘッダーの読み取りを回避できます。

  const app = new Koa({
    proxy: true,
    maxIpsCount: 1, // only one proxy in front of the server
  });

  // request.header['X-Forwarded-For'] === [ '127.0.0.1', '127.0.0.2' ];
  // ctx.ips === [ '127.0.0.2' ];

request.subdomains

サブドメインを配列として返します。

サブドメインとは、アプリのメインドメインの前にあるホストのドット区切り部分です。デフォルトでは、アプリのドメインはホストの最後の2つの部分と見なされます。これはapp.subdomainOffsetを設定することで変更できます。

例えば、ドメインが"tobi.ferrets.example.com"の場合:app.subdomainOffsetが設定されていない場合、ctx.subdomains["ferrets", "tobi"]です。app.subdomainOffsetが3の場合、ctx.subdomains["tobi"]です。

request.is(types...)

着信リクエストに"Content-Type"ヘッダーフィールドが含まれており、そのフィールドに指定されたMIMEtypeのいずれかが含まれているかどうかを確認します。リクエストボディがない場合はnullを返します。コンテンツタイプがない場合、または一致に失敗した場合はfalseを返します。それ以外の場合は、一致するコンテンツタイプを返します。

// With Content-Type: text/html; charset=utf-8
ctx.is('html'); // => 'html'
ctx.is('text/html'); // => 'text/html'
ctx.is('text/*', 'text/html'); // => 'text/html'

// When Content-Type is application/json
ctx.is('json', 'urlencoded'); // => 'json'
ctx.is('application/json'); // => 'application/json'
ctx.is('html', 'application/*'); // => 'application/json'

ctx.is('html'); // => false

例えば、特定のルートに画像のみを送信するようにしたい場合

if (ctx.is('image/*')) {
  // process
} else {
  ctx.throw(415, 'images only!');
}

コンテンツネゴシエーション

Koaのrequestオブジェクトには、acceptsnegotiatorによって提供される便利なコンテンツネゴシエーションユーティリティが含まれています。これらのユーティリティは

タイプが指定されていない場合、許容されるすべてのタイプが返されます。

複数のタイプが指定されている場合、最適な一致が返されます。一致が見つからない場合はfalseが返され、クライアントに406 "Not Acceptable"レスポンスを送信する必要があります。

任意のタイプが許容されるアクセプトヘッダーがない場合、最初のタイプが返されます。したがって、指定するタイプの順序は重要です。

request.accepts(types)

指定されたtype(s)が許容されるかどうかを確認し、trueの場合は最適な一致を返し、それ以外の場合はfalseを返します。type値は、"application/json"などの1つ以上のMIMEタイプ文字列、"json"などの拡張子名、または["json", "html", "text/plain"]などの配列にすることができます。

// Accept: text/html
ctx.accepts('html');
// => "html"

// Accept: text/*, application/json
ctx.accepts('html');
// => "html"
ctx.accepts('text/html');
// => "text/html"
ctx.accepts('json', 'text');
// => "json"
ctx.accepts('application/json');
// => "application/json"

// Accept: text/*, application/json
ctx.accepts('image/png');
ctx.accepts('png');
// => false

// Accept: text/*;q=.5, application/json
ctx.accepts(['html', 'json']);
ctx.accepts('html', 'json');
// => "json"

// No Accept header
ctx.accepts('html', 'json');
// => "html"
ctx.accepts('json', 'html');
// => "json"

ctx.accepts()は何度でも呼び出すことができますし、switch文を使用することもできます。

switch (ctx.accepts('json', 'html', 'text')) {
  case 'json': break;
  case 'html': break;
  case 'text': break;
  default: ctx.throw(406, 'json, html, or text only');
}

request.acceptsEncodings(encodings)

encodingsが許容されるかどうかを確認し、trueの場合は最適な一致を返し、それ以外の場合はfalseを返します。identityをエンコーディングの1つとして含める必要があります!

// Accept-Encoding: gzip
ctx.acceptsEncodings('gzip', 'deflate', 'identity');
// => "gzip"

ctx.acceptsEncodings(['gzip', 'deflate', 'identity']);
// => "gzip"

引数が指定されていない場合、すべての許容エンコーディングが配列として返されます。

// Accept-Encoding: gzip, deflate
ctx.acceptsEncodings();
// => ["gzip", "deflate", "identity"]

クライアントが明示的にidentity;q=0を送信した場合、identityエンコーディング(エンコーディングなしを意味する)は許容されない可能性があります。これは極端なケースですが、このメソッドがfalseを返すケースを処理する必要があります。

request.acceptsCharsets(charsets)

charsetsが許容されるかどうかを確認し、trueの場合は最適な一致を返し、それ以外の場合はfalseを返します。

// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
ctx.acceptsCharsets('utf-8', 'utf-7');
// => "utf-8"

ctx.acceptsCharsets(['utf-7', 'utf-8']);
// => "utf-8"

引数が指定されていない場合、すべての許容charsetが配列として返されます。

// Accept-Charset: utf-8, iso-8859-1;q=0.2, utf-7;q=0.5
ctx.acceptsCharsets();
// => ["utf-8", "utf-7", "iso-8859-1"]

request.acceptsLanguages(langs)

langsが許容されるかどうかを確認し、trueの場合は最適な一致を返し、それ以外の場合はfalseを返します。

// Accept-Language: en;q=0.8, es, pt
ctx.acceptsLanguages('es', 'en');
// => "es"

ctx.acceptsLanguages(['en', 'es']);
// => "es"

引数が指定されていない場合、すべての許容言語が配列として返されます。

// Accept-Language: en;q=0.8, es, pt
ctx.acceptsLanguages();
// => ["es", "pt", "en"]

request.idempotent

リクエストがべき等であるかどうかを確認します。

request.socket

リクエストソケットを返します。

request.get(field)

大文字と小文字を区別しないfieldを使用してリクエストヘッダーを返します。

レスポンス

KoaのResponseオブジェクトは、Nodeの標準的なレスポンスオブジェクトの上位に構築された抽象化レイヤーであり、日常的なHTTPサーバー開発に役立つ追加機能を提供します。

API

response.header

レスポンスヘッダーオブジェクト。

response.headers

レスポンスヘッダーオブジェクト。response.headerのエイリアスです。

response.socket

レスポンスソケット。request.socketと同様にnet.Socketインスタンスを指します。

response.status

レスポンスステータスを取得します。デフォルトでは、Nodeのres.statusCode200をデフォルトとするのに対し、response.status404に設定されます。

response.status=

数値コードでレスポンスステータスを設定します。

注記: これらの文字列を暗記する必要はありません。タイプミスがあればエラーがスローされ、このリストが表示されて修正できます。

response.status のデフォルトは 404 に設定されているため、ボディなしで異なるステータスを持つレスポンスを送信するには、次のようにします。

ctx.response.status = 200;

// Or whatever other status
ctx.response.status = 204;

response.message

レスポンスのステータスメッセージを取得します。デフォルトでは、response.messageresponse.status に関連付けられています。

response.message=

レスポンスのステータスメッセージを指定された値に設定します。

response.length=

レスポンスの Content-Length を指定された値に設定します。

response.length

存在する場合、レスポンスの Content-Length を数値として返します。可能であれば ctx.body から推測するか、undefined を返します。

response.body

レスポンスのボディを取得します。

response.body=

レスポンスのボディを以下のいずれかに設定します。

response.status が設定されていない場合、Koa は response.body に応じてステータスを 200 または 204 に自動的に設定します。具体的には、response.body が設定されていないか、null または undefined として設定されている場合、Koa は response.status204 に自動的に設定します。他のステータスでコンテンツなしのレスポンスを送信する必要がある場合は、次のように 204 ステータスをオーバーライドする必要があります。

// This must be always set first before status, since null | undefined
// body automatically sets the status to 204
ctx.body = null;
// Now we override the 204 status with the desired one
ctx.status = 200;

Koa は、レスポンスボディとして設定できるすべてのものを保護するわけではありません。関数は意味のあるシリアル化を行いません。ブール値の返却はアプリケーションによっては意味がある場合があり、エラーは機能しますが、エラーのいくつかのプロパティは列挙できないため、意図したとおりに機能しない場合があります。アプリケーションごとにボディの型をアサートするミドルウェアを追加することをお勧めします。サンプルミドルウェアは次のとおりです。

app.use(async (ctx, next) => {
  await next()

  ctx.assert.equal('object', typeof ctx.body, 500, 'some dev did something wrong')
})

文字列

Content-Type は、デフォルトで text/html または text/plain に設定され、どちらもデフォルトの文字セットとして utf-8 が使用されます。Content-Length フィールドも設定されます。

バッファ

Content-Type は、デフォルトで application/octet-stream に設定され、Content-Length も設定されます。

ストリーム

Content-Type は、デフォルトで application/octet-stream に設定されます。

ストリームがレスポンスボディとして設定されるたびに、エラーをキャッチするために .onerrorerror イベントのリスナーとして自動的に追加されます。さらに、リクエストが閉じられると(早期に閉じられた場合でも)、ストリームは破棄されます。これらの2つの機能を必要としない場合は、ストリームをボディに直接設定しないでください。たとえば、プロキシでボディをHTTPストリームとして設定する場合、基盤となる接続が破壊されるため、これは望ましくない場合があります。

詳細については、https://github.com/koajs/koa/pull/612 を参照してください。

ストリームを自動的に破棄せずにストリームエラー処理の例を以下に示します。

const PassThrough = require('stream').PassThrough;

app.use(async ctx => {
  ctx.body = someHTTPStream.on('error', (err) => ctx.onerror(err)).pipe(PassThrough());
});

オブジェクト

Content-Type は、デフォルトで application/json に設定されます。これには、プレーンオブジェクト { foo: 'bar' } と配列 ['foo', 'bar'] が含まれます。

response.get(field)

大文字と小文字を区別しない field を使用して、レスポンスヘッダーフィールドの値を取得します。

const etag = ctx.response.get('ETag');

response.has(field)

名前で識別されるヘッダーが現在送信ヘッダーに設定されている場合、true を返します。ヘッダー名の照合は大文字と小文字を区別しません。

const rateLimited = ctx.response.has('X-RateLimit-Limit');

response.set(field, value)

レスポンスヘッダー fieldvalue に設定します。

ctx.set('Cache-Control', 'no-cache');

response.append(field, value)

val を持つ追加のヘッダー field を追加します。

ctx.append('Link', '<http://127.0.0.1/>');

response.set(fields)

オブジェクトを使用して、いくつかのレスポンスヘッダー fields を設定します。

ctx.set({
  'Etag': '1234',
  'Last-Modified': date
});

これは、setHeader に委譲され、指定されたキーでヘッダーを設定または更新し、ヘッダー全体をリセットしません。

response.remove(field)

ヘッダー field を削除します。

response.type

"charset"などのパラメータのないレスポンスContent-Typeを取得します。

const ct = ctx.type;
// => "image/png"

response.type=

MIME文字列またはファイル拡張子を使用してレスポンスContent-Typeを設定します。

ctx.type = 'text/plain; charset=utf-8';
ctx.type = 'image/png';
ctx.type = '.png';
ctx.type = 'png';

注: 必要に応じて、charset が選択されます。たとえば、response.type = 'html' は "utf-8" をデフォルトで使用します。charset を上書きする必要がある場合は、ctx.set('Content-Type', 'text/html') を使用して、レスポンスヘッダーフィールドを値に直接設定します。

response.is(types...)

ctx.request.is() と非常によく似ています。レスポンスタイプが指定されたタイプのいずれかであるかどうかを確認します。これは、レスポンスを操作するミドルウェアを作成する場合に特に役立ちます。

たとえば、ストリームを除くすべてのHTMLレスポンスを縮小するミドルウェアです。

const minify = require('html-minifier');

app.use(async (ctx, next) => {
  await next();

  if (!ctx.response.is('html')) return;

  let body = ctx.body;
  if (!body || body.pipe) return;

  if (Buffer.isBuffer(body)) body = body.toString();
  ctx.body = minify(body);
});

response.redirect(url, [alt])

url に [302] リダイレクトを実行します。

文字列 "back" は、参照元が存在しない場合、alt または "/" が使用される参照元サポートを提供するために特別な扱いを受けます。

ctx.redirect('back');
ctx.redirect('back', '/index.html');
ctx.redirect('/login');
ctx.redirect('http://google.com');

デフォルトのステータス 302 を変更するには、この呼び出しの前または後にステータスを割り当てます。ボディを変更するには、この呼び出しの後に割り当てます。

ctx.status = 301;
ctx.redirect('/cart');
ctx.body = 'Redirecting to shopping cart';

response.attachment([filename], [options])

Content-Disposition を "attachment" に設定して、クライアントにダウンロードを促すように指示します。オプションでダウンロードのfilenameといくつかのオプションを指定します。

response.headerSent

レスポンスヘッダーが既に送信されているかどうかを確認します。クライアントにエラーを通知できるかどうかを確認するのに役立ちます。

response.lastModified

存在する場合、Last-Modified ヘッダーを Date として返します。

response.lastModified=

適切なUTC文字列としてLast-Modifiedヘッダーを設定します。Dateまたは日付文字列として設定できます。

ctx.response.lastModified = new Date();

response.etag=

ラップされた"を含むレスポンスのETagを設定します。対応するresponse.etagゲッターはありません。

ctx.response.etag = crypto.createHash('md5').update(ctx.body).digest('hex');

response.vary(field)

field で変更します。

response.flushHeaders()

設定されたヘッダーをフラッシュし、ボディを開始します。

スポンサー

Apex Ping は、Koaのオリジナル作成者の一人による、美しく使いやすいウェブサイトとAPIのアップタイム監視ソリューションです。

リンク

Koaのサードパーティミドルウェア、実行可能な完全な例、詳細なガイドなどを発見するためのコミュニティリンク!質問がある場合は、IRCに参加してください!