メインコンテンツまでスキップ

Middleware

Middleware を使うと、リクエストが完了する前にコードを実行できます。そして、送られてきたリクエストに基づいて、レスポンスを書き換えたり、リダイレクトしたり、リクエストやレスポンスのヘッダーを変更したり、直接レスポンスしたりすることで、レスポンスを変更できます。

Middleware はキャッシュされたコンテンツとルートがマッチングされる前に実行されます。詳細はパスのマッチングを参照してください。

規約

Middleware を定義するには、プロジェクトのルートにある middleware.ts (または .js) ファイルを使用する。例えば、pagesapp と同じ階層、または必要に応じて src 内に置く。

Example

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('/home', request.url))
}

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

マッチングパス

Middleware はプロジェクト内のすべてのルートに対して呼び出されます。実行順序は以下のとおりです:

  1. next.config.jsheaders
  2. next.config.jsredirects
  3. Middleware(rewritesredirects など)
  4. beforeFiles (rewrites) from next.config.js.
  5. ファイルシステムのルート(public/_next/static/pages/app/ など)
  6. afterFiles (rewrites) from next.config.js.
  7. 動的ルート (/blog/[slug])
  8. next.config.jsfallback (rewrites)

Middleware を実行するパスを定義する方法は 2 つあります:

  1. カスタムマッチャー設定
  2. 条件文

マッチャー

matcherを使用すると、特定のパスで実行する Middleware をフィルタリングできます。

middleware.js
export const config = {
matcher: '/about/:path*',
}

配列構文で、単一のパスまたは複数のパスにマッチさせることができます。

middleware.js
export const config = {
matcher: ['/about/:path*', '/dashboard/:path*'],
}

matcherの設定は完全な正規表現を許すので、負のルックアヘッドや文字マッチのようなマッチングがサポートされます。特定のパス以外をマッチさせる負のルックヘッドの例をここで見ることができます。

middleware.js
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).*)',
],
}

Good to know: matcherの値は、ビルド時に静的に解析できるように定数である必要があります。変数のような動的な値は無視されます。

設定されたマッチャー

  1. /で始まらなければならない。
  2. 名前付きパラメータを含むことができる:about/:path/about/a/about/b にマッチするが、 /about/a/c にはマッチしない。
  3. :で始まる)名前付きパラメータに修飾子をつけることができる: about/:path*/about/a/b/c にマッチします。?はゼロか 1 つ、+は 1 つ以上です。
  4. 括弧で囲まれた正規表現が使える: /about/(.*)/about/:path* と同じ。

詳細はpath-to-regexpを参照してください。

Good to know: 後方互換性のため、Next.js は常に /public/public/index とみなします。したがって、/public/:path のマッチャーはマッチします。

条件文

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))
}

if (request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.rewrite(new URL('/dashboard/user', request.url))
}
}

NextResponse

NextResponse API を使うと、以下のことができます。

  • リクエストを別の URL に redirect する。
  • 指定した URL を表示してレスポンスを rewrite する。
  • API Routes、getServerSideProps および rewrite 先のリクエストヘッダを設定する。
  • レスポンスクッキーを設定する。
  • レスポンスヘッダの設定する。

Middleware からレスポンスを生成するには、次のようにします。

  1. レスポンスを生成するルート Page または Edge API Routerewrite します。
  2. NextResponse を直接返す。レスポンスの生成を参照してください。

クッキーは通常のヘッダーです。リクエストでは Cookie ヘッダに格納されます。レスポンスでは Set-Cookie ヘッダに格納されます。Next.js は NextRequestNextResponsecookies 拡張機能を通して、これらのクッキーにアクセスし、操作する便利な方法を提供します。

  1. リクエストに対して、get, getAll, set, delete のメソッドが用意されています。hasでクッキーの存在を確認したり、clearですべてのクッキーを削除したりできます。
  2. 送信レスポンスでは、cookiesgetgetAllsetdelete メソッドを持っています。
middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
// Assume a "Cookie:nextjs=fast" header to be present on the incoming request
// Getting cookies from the request using the `RequestCookies` API
let cookie = request.cookies.get('nextjs')
console.log(cookie) // => { name: 'nextjs', value: 'fast', Path: '/' }
const allCookies = request.cookies.getAll()
console.log(allCookies) // => [{ name: 'nextjs', value: 'fast' }]

request.cookies.has('nextjs') // => true
request.cookies.delete('nextjs')
request.cookies.has('nextjs') // => false

// Setting cookies on the response using the `ResponseCookies` API
const response = NextResponse.next()
response.cookies.set('vercel', 'fast')
response.cookies.set({
name: 'vercel',
value: 'fast',
path: '/',
})
cookie = response.cookies.get('vercel')
console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/' }
// The outgoing response will have a `Set-Cookie:vercel=fast;path=/test` header.

return response
}

Headers の設定

リクエストヘッダとレスポンスヘッダは NextResponse API を使って設定できます(requestヘッダの設定は Next.js v13.0.0 から)

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

export function middleware(request: NextRequest) {
// Clone the request headers and set a new header `x-hello-from-middleware1`
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-hello-from-middleware1', 'hello')

// You can also set request headers in NextResponse.rewrite
const response = NextResponse.next({
request: {
// New request headers
headers: requestHeaders,
},
})

// Set a new response header `x-hello-from-middleware2`
response.headers.set('x-hello-from-middleware2', 'hello')
return response
}

Good to know: バックエンドのウェブサーバーの設定によっては、431 Request Header Fields Too Largeエラーを引き起こす可能性があるため、大きなヘッダーの設定は避けてください。

Response の作成

Responseインスタンスまたは NextResponse インスタンスを返すことで、Middleware から直接レスポンスを返すことができます。(これはNext.js v13.1.0から利用できます)

middleware.ts
import { NextRequest } from 'next/server'
import { isAuthenticated } from '@lib/auth'

// Limit the middleware to paths starting with `/api/`
export const config = {
matcher: '/api/:function*',
}

export function middleware(request: NextRequest) {
// Call our authentication function to check the request
if (!isAuthenticated(request)) {
// Respond with JSON indicating an error message
return Response.json(
{ success: false, message: 'authentication failed' },
{ status: 401 }
)
}
}

高度な Middleware フラグ

Next.js の v13.1 では、Middleware に 2 つの追加フラグが導入されました。 skipMiddlewareUrlNormalizeskipTrailingSlashRedirect です。

skipTrailingSlashRedirectは、Next.js のデフォルトのリダイレクトを無効にして、末尾のスラッシュを追加したり削除したりできます。これにより、Middleware 内部でカスタムの処理を行うことができるようになり、一部のパスでは末尾のスラッシュを維持し、他のパスでは維持しないようにできます。

next.config.js
module.exports = {
skipTrailingSlashRedirect: true,
}
middleware.js
const legacyPrefixes = ['/docs', '/blog']

export default async function middleware(req) {
const { pathname } = req.nextUrl

if (legacyPrefixes.some((prefix) => pathname.startsWith(prefix))) {
return NextResponse.next()
}

// apply trailing slash handling
if (
!pathname.endsWith('/') &&
!pathname.match(/((?!\.well-known(?:\/.*)?)(?:[^/]+\/)*[^/]+\.\w+)/)
) {
req.nextUrl.pathname += '/'
return NextResponse.redirect(req.nextUrl)
}
}

skipMiddlewareUrlNormalizeは、Next.js が行う URL 正規化を無効にし、直接訪問とクライアント遷移の処理を同じにします。元の URL を使って完全に制御する必要がある高度なケースもありますが、そのような場合はこの機能を利用できます。

next.config.js
module.exports = {
skipMiddlewareUrlNormalize: true,
}
middleware.js
export default async function middleware(req) {
const { pathname } = req.nextUrl

// GET /_next/data/build-id/hello.json

console.log(pathname)
// with the flag this now /_next/data/build-id/hello.json
// without the flag this would be normalized to /hello
}

ランタイム

Middleware は現在、Edge ランタイムのみをサポートしています。Node.js ランタイムは使用できません。

Version History

VersionChanges
v13.1.0高度な Middleware フラグの追加
v13.0.0Middleware はリクエストヘッダ、レスポンスヘッダを変更し、レスポンスを送信できる
v12.2.0Middleware は安定しています。アップグレードガイドを参照してください。
v12.0.9Edge ランタイムで URL の絶対指定が強制されるようになりました(PR)
v12.0.0Middleware(ベータ版)を追加しました