運用中のウェブアプリケーションに対して、セキュリティ面を考慮して以下のようなリクエスト制限をかける必要が生じたとします:

・(例えば)10分間で 100 回のリクエストを許可する
・許可数を超えた場合はリクエストを処理しない


クラウドやホスティングサーバーで運用する場合は、クラウド/ホスティング側にそのような機能が提供されていることもあると思います。が、もしそのような機能が提供されていない条件下でこのような要件が生じた場合、アプリケーションの実装としてリクエスト制限を用意する必要が出てくるかもしれません。 今回のブログエントリで紹介するのは、Node.js アプリケーションにリクエスト制限をかける実装方法です。


といっても Node.js (バージョン 14 以上)で Express ライブラリを使っている場合であれば express-rate-limit という Express 向けミドルウェアを使うことで簡単に実装できます:
20220228


以下でサンプルを紹介しますが、サンプルコードはこちらに公開しています:
https://github.com/dotnsf/express-rate-limit-sample


例えば現行のコード(app_old.js)が以下のようになっていたとします:
//. app_old.js
var express = require( 'express' ),
    app = express();

app.get( '/', function( req, res ){
  res.contentType( 'application/json; charset=utf-8' );
  res.write( JSON.stringify( { status: true }, null, 2 ) );
  res.end();
});

var port = process.env.PORT || 8080;
app.listen( port );
console.log( "server starting on " + port + " ..." );

"GET /" リクエストに対して "{ status: true }" を返すだけの内容ですが、処理内容自体はもっと複雑でも構いません。

このアプリケーションに「10分間で 100 回」というリクエスト制限をかける場合は以下のようなコード(app_new.js)に変更します:
//. app_new.js
var express = require( 'express' ),
    app = express();

//. rate limit : 100 times per 10 minutes
var rate = require( 'express-rate-limit' );
var limit = rate({
  windowMs: 10*60*1000,
  max: 100,
  standardHeaders: true,
  legacyHeaders: false
});
app.use( limit );

app.get( '/', function( req, res ){
  res.contentType( 'application/json; charset=utf-8' );
  res.write( JSON.stringify( { status: true }, null, 2 ) );
  res.end();
});

var port = process.env.PORT || 8080;
app.listen( port );
console.log( "server starting on " + port + " ..." );

express-rate-limit ライブラリをインスタンス化して、属性を指定して app.use() でリクエスト処理前に実行されるようにしています。なお各属性値は以下のような意味です:
・windowMs: 制限をかける時間(ミリ秒)
・max: windowMs で定義した時間でのリクエスト処理上限数
・standardHeaders: "RateLimit-*" でリクエスト制限情報を HTTP ヘッダに含める※
・legacyHeaders: "X-RateLimit-*" でリクエスト制限情報を HTTP ヘッダに含める※

※上述のサンプルでは standardHeaders: true, legacyHeaders: false に指定している

これだけでアプリケーションレベルでリクエスト制限を実装できます。 ただし、この制限は「1インスタンスごとの制限」である点に注意が必要です。クラウド的な言い方だと「1コンテナ」あたりでこの制限が有効になりますが、複数インスタンスで運用した場合、例えば可用性を高める目的で3つのコンテナを起動して運用した場合は、事実上設定値の3倍のリクエスト処理を受け付けることになる、という点に注意が必要です。