🌊

【Next.js】middlewareを試してみた

2022/11/16に公開

概要

Next.jsでversion12からMiddlewareと呼ばれるものが導入されました。
現在はversion13.0.0となっています。beta版からは仕様が変わったみたいですね。

今回は実際に試してみたのですが、beta版の記事しか見当たらないく四苦八苦したので自分用にメモ。

以下公式サイト

https://nextjs.org/docs/advanced-features/middleware

追記:ベーシック認証をやってみた。
https://zenn.dev/kiriyama/articles/630603f64fefa2

Middlewareとは?

公式サイトだと下記のように書いてあります。

ミドルウェアを使用すると、リクエストが完了する前にコードを実行できます。その後、受信したリクエストに基づいて、リクエストまたはレスポンス ヘッダーを書き換え、リダイレクト、変更するか、直接応答することで、レスポンスを変更できます。

つまりは、ユーザーからのリクエストが来た時にページをレスポンスで返す前にコードを実行することができるのでリダイレクトをしたり、Basic認証をかけたり、みたいなことができます。

設置場所

実際にNext.jsでmiddlewareを使用する場合は、beta版の時はpagesフォルダ配下に_middleware.tsなどに設置するとpages配下のfileに対して実行されていて、pages/about/など下の階層に_middleware.tsを設置するとそのフォルダに対して実行されていたようです。

ただ正式にリリースされた後はいわゆる_middleware.tsをネストする方法は廃止になったようで、現在は、middleware.tsもしくはmiddleware.jsファイルをルートまたはsrcディレクトリ ( と同じレベル)に作成するようで、プロジェクト内に middleware は1つしか存在できないようです。
今回の実験では以下の階層に設置してみた。

ベースとなるコード

公式サイトにサンプルが載っていたので、以下のコードが基本??となるのかな。
middlewareという関数をexportするようで引数にはrequest: NextRequestという事でユーザーからのリクエストを受け取れるらしい。

middleware.ts
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/about-2', request.url))
}

// See "Matching Paths" below to learn more
export const config = {
  matcher: '/about/:path*',
}

特定のパスで実行するには?

特定のページの場合はリダイレクトとかしたい場合、beta版だと特定のフォルダ配下に_middleware.tsをネストして設置すれば良かった?と思われるが、リリース版は違う。公式サイトにも記載があるが、2パターンあるっぽい。

条件分岐

URLのパスを調べてif構文で条件分岐するやり方。公式サイトより参照

middleware.ts
// middleware.ts

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname.startsWith('/about')) {
    return NextResponse.rewrite(new URL('/about-2', request.url))
  }
}

上記の場合だと、request.nextUrl.pathname.startsWith('/about')は、request.nextUrl.pathnameでパスを取得してsartsWith()で引数に指定された文字列で始まるかを判定してる。
もしtrueなら/about-2のページを表示する。といった流れになっているようです。

matcherを利用する

公式サイトにあるサンプルコードからの抜粋ですが。
https://nextjs.org/docs/advanced-features/middleware#matcher

middleware.ts
//特定のパス
export const config = {
  matcher: '/about/:path*',
}

//複数のパス
  matcher: ['/about/:path*', '/dashboard/:path*'],

変数configmatcherに複数の場合は配列のように指定すればいいらしい。

実際に実装してみる。

実際にmiddlewareを使ってみる。Next.jsのバージョンは13です。
トップページからAboutページへアクセスしたらリダイレクトするといった流れにしようかと思います。

ディレクトリ構成

以下、ディレクトリ構成と必要なファイル。
・pages/index.tsx
・pages/about.tsx
・pages/redirect.tsx
・middleware.ts

about.tsxredirect.tsxは適当なファイル名ですl。

各ファイル

まずはmiddlleware.ts以外のファイルです。今回はmiddlewareが動くかどうかを知りたいだけなので、簡素で十分です。
今回はAboutページ自体は、実際に表示されることがないのでファイルだけ用意してます。

pages/index.tsx
import Link from 'next/link'

export default function Home() {
  return (
    <div>
     <h1>トップページ</h1>
      <Link href="/about">aboutページ</Link> 
    </div>
  )
}
pages/about.tsx
import Link from 'next/link'

export default function About() {
  return (
    <div>
     <h1>Aboutページ</h1>
    </div>
  )
}
pages/redirect.tsx
import Link from 'next/link'

export default function About() {
  return (
    <div>
     <h1>リダイレクトページ</h1>
      <Link href="/">トップ</Link>  
    </div>
  )
}

middleware.ts

公式サイトのコードをそのまま。

middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function middleware(req: NextRequest) {
    return NextResponse.redirect(new URL('/redirect', req.url))
}
export const config = {
    matcher: '/about',
  }

matcher/aboutのパスを指定して、このページにきたらNextResponse.redirectでリダイレクトページへ飛ばしています。
実際に確認すると下記のようになります。

まとめ

とりあえず実際に試してみたが、今度はBasic認証を試してみる。

https://zenn.dev/kj455/articles/486ddbfe3520be
https://dabohaze.site/next-js-12-2-0-middleware-basic-authentication/
https://zenn.dev/canesro/articles/41ca9c6c49b9fb

Discussion