ミドルウェアを使用して要求ライフサイクルを管理する

完了

Tailwind Traders では、Web API をセキュリティで保護したいと考えています。 場合によっては、要求が Web アプリケーションに到達したときに、次のことを確認する必要があります。

  • 認証: ユーザーが誰であるか
  • 承認: ユーザーは何を表示または実行できるか

要求の手順

要求を一連の手順として処理することを考えてみましょう。 リソースを処理するためにユーザーがログインする必要がある場合、手順は次のようになります。

  1. 前処理: 要求が処理される前のコード実行のための省略可能なステップ。

    例としては、要求ヘッダーを通してユーザーが適切な資格情報を送信したことを特定することが挙げられます。 資格情報が確認されると、要求が次の手順に送信されます。。 ログ記録に失敗した場合、サーバーは 401 HTTP 応答を返します。

  2. 処理: 何らかの種類のデータ ソース (データベースや API エンドポイントなど) と通信するなど、要求の処理を行います。

    要求によってリソースが適切に確認されると、このステップでリソースが返されます。

  3. 後処理: 要求が完了した後のコード実行のための省略可能なステップ。

    例としては、監視目的で結果をログに記録することが挙げられます。

Express フレームワークには、この方法で要求を処理するためのサポートが組み込まれています。 要求に対して前処理または後処理を実行するには、次の構文形式を使用して、Express app オブジェクトで use() メソッドを実装します。

app.use((req, res, next) => {})

use() メソッドに渡されるメソッドには、次のパラメーターがあります。

  • req: 要求ヘッダーと呼び出し元 URL を含む受信要求。 また、要求でクライアントからデータが送信された場合は、データの本体が含まれることがあります。
  • res: 呼び出し元のクライアントに返信するヘッダーやデータなど、情報の書き込みに使用する応答ストリーム。
  • next: スタック内の "次の" ミドルウェア関数。 next() 関数が呼び出されない場合、要求の処理は停止します。 要求が成功した場合は、next() を呼び出して応答に変更を加えたり、結果をログに記録したりできます。

要求パイプライン

前処理または後処理ミドルウェアを使用してメリットを得られるルートがある場合は、ソース コード ファイルに関数を次のように設定します。

  • 要求の前に実行される必要があるミドルウェア (前処理) は、実際の要求の前に定義します。
  • 要求の後に実行される必要があるミドルウェア (後処理) は、実際の要求の後で定義します。

次の例を見てください。

app.use((req, res, next) => {
  // Pre request
})
app.get('/protected-resource', () => {
  // Handle the actual request
})
app.use((req, res, next) => {
  // Post request
})

app.get('/login', () => {})

次のように、前処理ミドルウェアを要求ハンドラーへの引数として実行することもできます。

app.get(
  '/<some route>',
 () => {
   // Pre request middleware
 }, () => {
   // Handle the actual request
 })

Express.js のミドルウェア関数は、コード内で定義された順序で順番に実行されるため、その順序は非常に重要です。 これは、ミドルウェア関数をルート ハンドラーの後に配置すると、そのルートに対しては実行されないことを意味します。

ルート管理のベスト プラクティス

ミドルウェア関数の順序を管理するためのベスト プラクティスを次に示します。

  • グローバル ミドルウェアを一番上に配置します。すべてのルートに適用されるミドルウェア関数は、コードの先頭に、どのルート ハンドラーよりも前に配置する必要があります。 これにより、すべての要求に対して確実に実行されます。

  • 具体性に従ってミドルウェアの順序を決めます。より一般的なミドルウェア関数の後に、より具体的なミドルウェア関数を配置する必要があります。 これにより、一般的なミドルウェア関数ですべてのルートの一般的なタスクを処理でき、特定のもので特定のルートのタスクを処理できます。

  • エラー処理ミドルウェアを最後に配置します。4 つの引数を持つミドルウェア関数は、エラー処理ミドルウェアとして扱われます。 これらは、他のすべてのミドルウェアとルート ハンドラーの後、ミドルウェア スタックの末尾に配置する必要があります。

次に例を示します。

const express = require('express');
const app = express();

// Global middleware
app.use((req, res, next) => {
  console.log('This is a global middleware');
  next();
});

// Route handler
app.get('/', (req, res, next) => {
  console.log('This is a route handler');
  next();
});

// Specific middleware
app.use((req, res, next) => {
  console.log('This is a specific middleware');
  next();
});

// Error-handling middleware
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

app.listen(3000);