🤖

Next.js の API で ip アドレスで rate limit をかける方法

2021/12/12に公開

はじめに

Next.js の API routes で、一定期間内にリクエストを送れる回数を IP アドレスで制限(rate limit)する方法について調べたので、メモとして残しておきます。

https://github.com/vercel/next.js/tree/canary/examples/api-routes-rate-limit

↑ こちらの公式例を少し改良したものです。

ライブラリ インストール

yarn add lru-cache request-ip
yarn add -D @types/lru-cache @types/request-ip

コード

project/src/lib/limitChecker.ts
import LRU from "lru-cache";

import type { NextApiResponse } from "next";

type CheckLimitFunc = () => {
  check: (res: NextApiResponse, limit: number, ipAddress: string) => Promise<void>;
};
export const LimitChecker: CheckLimitFunc = () => {
  const tokenCache = new LRU<string, number>({
    max: 500, // Max 500 users per interval
    maxAge: 1000 * 60 * 5, // 5分,
  });

  return {
    check: (res, limit, token): Promise<void> =>
      new Promise((resolve, reject) => {
        const tokenCount = tokenCache.get(token) || 0;

        const currentUsage = tokenCount + 1;
        tokenCache.set(token, currentUsage);

        const isRateLimited = currentUsage > limit;
        res.setHeader("X-RateLimit-Limit", limit);
        res.setHeader("X-RateLimit-Remaining", isRateLimited ? 0 : limit - currentUsage);

        return isRateLimited ? reject("Too Many Requests") : resolve();
      }),
  };
};
project/src/pages/api/hello.page.ts
// pageExtensions の設定をしているので .page.ts になっています
import requestIp from "request-ip";

import type { NextApiRequest, NextApiResponse } from "next";

import { LimitChecker } from "@/lib/limitChecker";

const limitChecker = LimitChecker();

type Data = {
  text: string;
  clientIp: string;
};
export default async function handler(req: NextApiRequest, res: NextApiResponse<Data>): Promise<void> {
  const clientIp = requestIp.getClientIp(req) || "IP_NOT_FOUND";

  try {
    await limitChecker.check(res, 3, clientIp);
  } catch (error) {
    console.error(error);

    res.status(429).json({
      text: `Rate Limited`,
      clientIp: clientIp,
    });
    return;
  }

  res.status(200).json({
    text: `テキスト`,
    clientIp: clientIp,
  });
}

おわりに

簡単にではありますが、API routes に対するリクエスト回数の制限をかける方法でした。
bot 等からの大量のリクエストに対する対策の一つにはなると思います 💪

参考にさせていただいたサイト

https://github.com/vercel/next.js/tree/canary/examples/api-routes-rate-limit

https://pretagteam.com/question/how-to-get-the-ip-address-of-the-client-from-server-side-in-nextjs-app

GitHubで編集を提案

Discussion