⬛️

Next.jsのmiddleware.tsを利用していたら画像が表示されなくなった

2023/10/11に公開

TL;DR

middleware.ts は、 public/ やビルド後の _next/ ディレクトリ内のファイルのリクエストに対しても動作するため、利用するときには注意しましょう。

何が起こっていたか

開発中に、画像がリンク切れ表示になっていることに気づきました。

何が原因だったのか

画像のURLをブラウザで確認してみたところ、権限エラーのページが表示されました。

その後、DevToolsのNetworkタブでどうなっているかを確認しました。
画像は /public ディレクトリに置いていて、ビルド時に _next/static ディレクトリにコピーされているものでした。
その画像が307(Temporary Redirect)で権限エラーのページへリダイレクトされていました。

この挙動の問題がどこなのか実装を確認したところ、 middleware.ts で特定のパス以外では権限エラーページへのリダイレクトが行われていることがわかりました。

middleware.ts はどこまで有効なのか

なぜこうなるのかを調べたところ、middleware.tspublic/ に配置したファイルや _next/ などNext.jsで配信しているファイルにも機能する ことがわかりました。

Matching Pathsより引用すると、優先順位は以下のとおりになっており、5番目に Filesystem routes (public/, _next/static/, pages/, app/, etc.) と書かれています。

  1. headers from next.config.js
  2. redirects from next.config.js
  3. Middleware (rewrites, redirects, etc.)
  4. beforeFiles (rewrites) from next.config.js
  5. Filesystem routes (public/, _next/static/, pages/, app/, etc.)
  6. afterFiles (rewrites) from next.config.js
  7. Dynamic Routes (/blog/[slug])
  8. fallback (rewrites) from next.config.js

今回の原因としては、

  • 5番目に書かれている内容(Filesystem router)を見逃していた
  • 3番目のMiddleware(= middleware.ts)が先にリダイレクト処理を済ませていたため、5番目にたどり着いていなかった

ということでした。

対処方法

公式ドキュメントのMatcherセクションに記載されているように、 middleware.ts に除外したいパスを記述しました。

export const config = {
  matcher: [
    /*
     * Match all request paths except for the ones starting with:
     * - api (API routes)
     * - _next/static (static files)
     * - _next/image (image optimization files)
     * - favicon.ico (favicon file)
     */
    '/((?!api|_next/static|_next/image|favicon.ico).*)',
  ],
}

これにより、画像がリダイレクトされることなく表示されました。

まとめ

技術的な課題に取り組む際には、公式ドキュメントを隅々まで理解することが重要だと再認識しました...。

みなさんも公式ドキュメントを丁寧に読み、フレームワークを最大限に活用できるようになりましょう💪

Discussion