redirect

redirect関数を使用すると、ユーザーを別のURLにリダイレクトできます。redirectサーバーコンポーネントルートハンドラーサーバーアクションで使用可能です。

ストリーミングコンテキストで使用すると、クライアントサイドでリダイレクトを実行するためのmetaタグが挿入されます。サーバーアクションで使用すると、呼び出し元に303 HTTPリダイレクトレスポンスが返されます。それ以外の場合、307 HTTPリダイレクトレスポンスが返されます。

リソースが存在しない場合は、代わりにnotFound関数を使用できます。

リファレンス

パラメータ

redirect関数は2つの引数を受け取ります:

redirect(path, type)
パラメータタイプ説明
pathstringリダイレクト先のURL。相対パスまたは絶対パスを指定可能。
type'replace'(デフォルト)または 'push'(サーバーアクションではデフォルト)実行するリダイレクトのタイプ。

デフォルトでは、redirectサーバーアクションではpush(ブラウザの履歴スタックに新しいエントリを追加)、それ以外の場所ではreplace(ブラウザの履歴スタックで現在のURLを置換)を使用します。typeパラメータを指定することでこの動作を上書きできます。

typeパラメータはサーバーコンポーネントでは効果がありません。

戻り値

redirectは値を返しません。

動作

  • サーバーアクションとルートハンドラーでは、redirecttry/catchブロックの後に呼び出す必要があります。
  • 307(一時的)ではなく308(永続的)HTTPリダイレクトを返したい場合は、代わりにpermanentRedirect関数を使用できます。
  • redirectは内部的にエラーをスローするため、try/catchブロックの外で呼び出す必要があります。
  • redirectはレンダリングプロセス中にクライアントコンポーネントで呼び出せますが、イベントハンドラーでは呼び出せません。代わりにuseRouterフックを使用できます。
  • redirectは絶対URLも受け入れ、外部リンクへのリダイレクトに使用できます。
  • レンダリングプロセスの前にリダイレクトしたい場合は、next.config.jsまたはミドルウェアを使用してください。

サーバーコンポーネント

redirect()関数を呼び出すとNEXT_REDIRECTエラーがスローされ、スローされたルートセグメントのレンダリングが終了します。

import { redirect } from 'next/navigation'

async function fetchTeam(id: string) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}

export default async function Profile({
  params,
}: {
  params: Promise<{ id: string }>
}) {
  const { id } = await params
  const team = await fetchTeam(id)

  if (!team) {
    redirect('/login')
  }

  // ...
}
import { redirect } from 'next/navigation'

async function fetchTeam(id) {
  const res = await fetch('https://...')
  if (!res.ok) return undefined
  return res.json()
}

export default async function Profile({ params }) {
  const { id } = await params
  const team = await fetchTeam(id)

  if (!team) {
    redirect('/login')
  }

  // ...
}

豆知識: redirectはTypeScriptのnever型を使用しているため、return redirect()と書く必要はありません。

クライアントコンポーネント

redirectはクライアントコンポーネントで直接使用できます。

'use client'

import { redirect, usePathname } from 'next/navigation'

export function ClientRedirect() {
  const pathname = usePathname()

  if (pathname.startsWith('/admin') && !pathname.includes('/login')) {
    redirect('/admin/login')
  }

  return <div>Login Page</div>
}
'use client'

import { redirect, usePathname } from 'next/navigation'

export function ClientRedirect() {
  const pathname = usePathname()

  if (pathname.startsWith('/admin') && !pathname.includes('/login')) {
    redirect('/admin/login')
  }

  return <div>Login Page</div>
}

豆知識: サーバーサイドレンダリング (SSR) 中の初期ページロード時にクライアントコンポーネントでredirectを使用すると、サーバーサイドリダイレクトが実行されます。

redirectはサーバーアクションを通じてクライアントコンポーネントで使用できます。イベントハンドラーを使用してユーザーをリダイレクトする必要がある場合は、useRouterフックを使用できます。

'use client'

import { navigate } from './actions'

export function ClientRedirect() {
  return (
    <form action={navigate}>
      <input type="text" name="id" />
      <button>Submit</button>
    </form>
  )
}
'use client'

import { navigate } from './actions'

export function ClientRedirect() {
  return (
    <form action={navigate}>
      <input type="text" name="id" />
      <button>Submit</button>
    </form>
  )
}
'use server'

import { redirect } from 'next/navigation'

export async function navigate(data: FormData) {
  redirect(`/posts/${data.get('id')}`)
}
'use server'

import { redirect } from 'next/navigation'

export async function navigate(data) {
  redirect(`/posts/${data.get('id')}`)
}

よくある質問

redirectが307と308を使用する理由

redirect()を使用すると、一時リダイレクトには307、永続リダイレクトには308が使用されることに気付くかもしれません。従来は一時リダイレクトに302、永続リダイレクトに301が使用されていましたが、多くのブラウザは302を使用する際に、元のリクエストメソッドに関係なく、リダイレクトのリクエストメソッドをPOSTからGETに変更していました。

/usersから/peopleへのリダイレクトの例を考えてみましょう。新しいユーザーを作成するために/usersPOSTリクエストを送信し、302一時リダイレクトに従う場合、リクエストメソッドはPOSTからGETに変更されます。これは理にかなっていません。新しいユーザーを作成するには、GETリクエストではなくPOSTリクエストを/peopleに送信する必要があります。

307ステータスコードの導入により、リクエストメソッドがPOSTとして保持されるようになりました。

  • 302 - 一時リダイレクト、リクエストメソッドをPOSTからGETに変更
  • 307 - 一時リダイレクト、リクエストメソッドをPOSTとして保持

redirect()メソッドはデフォルトで302ではなく307を使用するため、リクエストは常にPOSTリクエストとして保持されます。

HTTPリダイレクトについてさらに学ぶ

バージョン履歴

バージョン変更点
v13.0.0redirectが導入されました。