Next.js Middlewareでのリダイレクト・書き換え・Cookie制御パターン

Next.js TypeScript Backend Frontend
結論

リダイレクトには redirect、内部転送には rewrite を使い、matcher で無限ループを防ぎます。

// Next.js公式仕様:middleware.ts の基本構成
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const token = request.cookies.get('auth-token')?.value;
  const { pathname } = request.nextUrl;

  // 1. 未認証ユーザーをログイン画面へリダイレクト
  if (!token && pathname.startsWith('/dashboard')) {
    const loginUrl = new URL('/login', request.url);
    return NextResponse.redirect(loginUrl);
  }

  // 2. Cookieの更新レスポンス生成
  const response = NextResponse.next();
  response.cookies.set('last-visited', Date.now().toString(), { httpOnly: true });
  return response;
}

// ⭕ 静的アセットと不要ルートを除外してパフォーマンス維持&ループ防止
export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

Next.js公式仕様:NextResponse 3大機能の比較

機能動作と結果主なユースケース
NextResponse.redirect(url)ブラウザのアドレスバー表記を変更して遷移認証ガード(ログインへ転送)、旧URLの移転
NextResponse.rewrite(url)アドレスバー表記はそのままで内部パスを描画マルチテナント、A/Bテスト、APIプロキシ遮蔽
response.cookies.set()レスポンスヘッダーの Set-Cookie を操作認証トークンの付与、訪問履歴の更新

実際に起こる障害:TOO_MANY_REDIRECTS 無限ループ事故

Middlewareで未認証ガードを書く際、対象パスの判定が甘いと以下の無限ループ障害が発生します。

HTTP ERROR 310 (net::ERR_TOO_MANY_REDIRECTS)

発生原因と対策

未認証ユーザーが /dashboard にアクセスした際、/login へリダイレクトを掛けます。この時、/login 自身も Middleware の判定対象に含まれており、かつ「現在のパスが /login であるか」の除外チェックがないと、/login へのアクセスに対してさらに /login へのリダイレクトが連続発火してブラウザがクラッシュ します。


設定手順

  1. ルートディレクトリ直下(または src/)に middleware.ts を配置する
  2. config.matcher を記述し、/_next/static, /_next/image, favicon.ico などの静的ファイルを対象外にする
  3. リダイレクト対象パスの判定時に pathname === '/login'/public ルートを除外条件に含める