تغییر مسیر
در Next.js چندین روش برای مدیریت هدایت (redirect) وجود دارد. این صفحه به تک تک گزینه های موجود، موارد استفاده و نحوه مدیریت تعداد زیادی از هدایت ها می پردازد.
| API | هدف | جایی که | کد وضعیت |
|---|---|---|---|
redirect | تغییر مسیر کاربر پس از جهش mutation یا رویداد | کامپوننت های سرور، اکشن های سرور، هندلرهای مسیر Server Components, Server Actions, Route Handlers | 307 (موقت) یا 303 (اکشن سرور Server Action) |
permanentRedirect | تغییر مسیر کاربر پس از جهش mutation یا رویداد | کامپوننت های سرور، اکشن های سرور، هندلرهای مسیر Server Components, Server Actions, Route Handlers | 308 (دائمی) |
useRouter | یک ناوبری سمت کلاینت انجام دهید | هندلرهای رویداد Event Handlers در کلاینت کامپوننت ها | N/A |
redirects in next.config.js | تغییر مسیر درخواست ورودی بر اساس یک مسیر | فایل next.config.js | 307 (موقت) یا 308 (دائمی) |
NextResponse.redirect | تغییر مسیر درخواست ورودی بر اساس یک شرط | میان افزار Middleware | هر |
تابع redirect
تابع redirect به شما امکان می دهد کاربر را به یک URL دیگر هدایت کنید. شما می توانید از redirect در کامپوننت های سمت سرور، هندلرهای مسیر و اکشن های سمت سرور Server Actions استفاده کنید.
redirect اغلب پس از یک تغییر یا رویداد استفاده می شود. به عنوان مثال، ایجاد یک پست:
'use server'
import { redirect } from 'next/navigation'
import { revalidatePath } from 'next/cache'
export async function createPost(id: string) {
try {
// Call database
} catch (error) {
// Handle errors
}
revalidatePath('/posts') // Update cached posts
redirect(`/post/${id}`) // Navigate to the new post page
}خوب است بدانید:
- تابع
redirectبه طور پیش فرض کد وضعیت 307 (هدایت موقت) را برمیگرداند. هنگامی که در یک اکشن سمت سرور استفاده می شود، کد وضعیت 303 (مشاهده دیگر) را برمیگرداند، که به طور معمول برای هدایت به صفحه موفقیت به عنوان نتیجه یک درخواست POST استفاده می شود.- تابع
redirectبه صورت داخلی خطا پرتاب می کند، بنابراین باید خارج از بلاک هایtry/catchفراخوانی شود.- تابع
redirectرا می توان در کامپوننت های سمت کاربر در طول فرآیند رندر فراخوانی کرد، اما در هندلرهای رویداد قابل فراخوانی نیست. به جای آن می توانید از هوک هوکuseRouterاستفاده کنید.- تابع
redirectهمچنین URL های مطلق absolute را می پذیرد و می تواند برای هدایت به لینک های خارجی استفاده شود.- اگر می خواهید قبل از فرآیند رندر، هدایت انجام دهید، از
next.config.jsیا Middleware استفاده کنید.
برای اطلاعات بیشتر به مرجع API redirect مراجعه کنید.
تابع permanentRedirect
تابع permanentRedirect به شما امکان می دهد کاربر را به صورت دائم به یک URL دیگر هدایت کنید. شما می توانید از permanentRedirect در کامپوننت های سرور، هندلرهای مسیر و اکشن های سرور استفاده کنید.
permanentRedirect اغلب پس از یک تغییر یا رویدادی که URL اصلی یک نهاد را تغییر می دهد، مانند به روز رسانی URL پروفایل کاربر پس از تغییر نام کاربری آن ها، استفاده می شود:
'use server'
import { permanentRedirect } from 'next/navigation'
import { revalidateTag } from 'next/cache'
export async function updateUsername(username: string, formData: FormData) {
try {
// Call database
} catch (error) {
// Handle errors
}
revalidateTag('username') // Update all references to the username
permanentRedirect(`/profile/${username}`) // Navigate to the new user profile
}خوب است بدانید:
- تابع
permanentRedirectبه طور پیش فرض کد وضعیت 308 (هدایت دائم) را برمیگرداند.- تابع
permanentRedirectهمچنین URL های مطلق absolute را می پذیرد و می تواند برای هدایت به لینک های خارجی استفاده شود.- اگر می خواهید قبل از فرآیند رندر، هدایت انجام دهید، از
next.config.jsیا Middleware استفاده کنید.
برای اطلاعات بیشتر به مرجع API permanentRedirect مراجعه کنید.
هوک useRouter()
اگر نیاز به هدایت درون یک هندلر رویداد در یک کامپوننت سمت کاربر دارید، می توانید از متد push از هوک useRouter استفاده کنید. برای مثال:
'use client'
import { useRouter } from 'next/navigation'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}خوب است بدانید:
- اگر نیازی به هدایت برنامه ریزی شده کاربر ندارید، از کامپوننت
<Link>استفاده کنید.
برای اطلاعات بیشتر به مرجع API useRouter مراجعه کنید.
redirects در next.config.js
گزینه redirects در فایل next.config.js به شما امکان می دهد مسیر یک درخواست ورودی را به یک مسیر مقصد دیگر هدایت کنید. این زمانی مفید است که ساختار URL صفحات را تغییر میدهید یا لیستی از هدایتها دارید که از قبل شناخته شدهاند.
redirects از تطبیق مسیر، هدر، کوکی و کوئری پشتیبانی میکند و انعطافپذیری لازم را برای هدایت کاربران بر اساس یک درخواست ورودی به شما میدهد.
برای استفاده از redirects، این گزینه را به فایل next.config.js خود اضافه کنید:
module.exports = {
async redirects() {
return [
// Basic redirect
{
source: '/about',
destination: '/',
permanent: true,
},
// Wildcard path matching
{
source: '/blog/:slug',
destination: '/news/:slug',
permanent: true,
},
]
},
}برای اطلاعات بیشتر به مرجع API redirects مراجعه کنید.
خوب است بدانید:
redirectsمیتواند کد وضعیت 307 (هدایت موقت) یا 308 (هدایت دائم) را با گزینهpermanentدائمی برگرداند.- تعداد
redirectsممکن است در پلتفرمهای مختلف محدودیت داشته باشد. برای مثال، در Vercel، حداکثر تعداد مجاز 1024 عدد است. برای مدیریت تعداد زیادی از هدایت (بیش از 1000)، راهحل سفارشی با استفاده از Middleware در نظر بگیرید. برای اطلاعات بیشتر به مدیریت هدایت در حجم بالا: managing redirects at scale مراجعه کنید.redirectsقبل از Middleware اجرا میشود.
NextResponse.redirect در Middleware
Middleware به شما امکان می دهد قبل از تکمیل یک درخواست، کد اجرا کنید. سپس بر اساس درخواست ورودی، با استفاده از NextResponse.redirect به یک URL دیگر هدایت کنید. این زمانی مفید است که بخواهید کاربران را بر اساس یک شرط (مانند احراز هویت، مدیریت جلسه و غیره) هدایت کنید یا تعداد زیادی از هدایت داشته باشید.
برای مثال، برای هدایت کاربر به صفحه /login در صورت عدم احراز هویت:
import { NextResponse, NextRequest } from 'next/server'
import { authenticate } from 'auth-provider'
export function middleware(request: NextRequest) {
const isAuthenticated = authenticate(request)
// If the user is authenticated, continue as normal
if (isAuthenticated) {
return NextResponse.next()
}
// Redirect to login page if not authenticated
return NextResponse.redirect(new URL('/login', request.url))
}
export const config = {
matcher: '/dashboard/:path*',
}خوب است بدانید:
- Middleware بعد از
redirectsدرnext.config.jsو قبل از رندر شدن صفحه اجرا میشود.
برای اطلاعات بیشتر به مستندات Middleware مراجعه کنید.
مدیریت ریدایرکت ها در حجم بالا (پیشرفته)
برای مدیریت تعداد زیادی از هدایت (بیش از 1000 عدد)، ممکن است ایجاد یک راهحل سفارشی با استفاده از Middleware را در نظر بگیرید. این کار به شما امکان میدهد بدون نیاز به راهاندازی مجدد برنامه، هدایتها را به صورت برنامهریزیشده مدیریت کنید.
برای انجام این کار، باید موارد زیر را در نظر بگیرید :
- ایجاد و ذخیره کردن نقشه هدایت (redirect map)
- بهینه سازی عملکرد جستجوی داده ها
مثال Next.js: برای اجرای توصیههای زیر، به مثال فیلتر میانافزار با بلوم (opens in a new tab) ما مراجعه کنید.
1. ایجاد و ذخیره کردن نقشه هدایت (redirect map)
نگاشت هدایت فهرستی از هدایتها است که میتوانید آنها را در یک پایگاه داده (معمولاً یک ذخیرهساز کلید-مقدار) یا فایل JSON ذخیره کنید.
ساختار داده زیر را در نظر بگیرید:
{
"/old": {
"destination": "/new",
"permanent": true
},
"/blog/post-old": {
"destination": "/blog/post-new",
"permanent": true
}
}در Middleware میتوانید از یک پایگاه داده مانند Vercel's Edge Config (opens in a new tab) یا Redis (opens in a new tab) بخوانید و کاربر را بر اساس درخواست ورودی هدایت کنید:
import { NextResponse, NextRequest } from 'next/server'
import { get } from '@vercel/edge-config'
type RedirectEntry = {
destination: string
permanent: boolean
}
export async function middleware(request: NextRequest) {
const pathname = request.nextUrl.pathname
const redirectData = await get(pathname)
if (redirectData && typeof redirectData === 'string') {
const redirectEntry: RedirectEntry = JSON.parse(redirectData)
const statusCode = redirectEntry.permanent ? 308 : 307
return NextResponse.redirect(redirectEntry.destination, statusCode)
}
// No redirect found, continue without redirecting
return NextResponse.next()
}2. بهینهسازی عملکرد جستجوی داده
خواندن یک مجموعه داده بزرگ برای هر درخواست ورودی میتواند کند و پرهزینه باشد. دو راه برای بهینهسازی عملکرد جستجوی داده وجود دارد:
- از یک پایگاه دادهای که برای خواندن سریع بهینهسازی شده است، مانند Vercel Edge Config (opens in a new tab) یا Redis (opens in a new tab) استفاده کنید.
- از یک استراتژی جستجوی داده مانند Bloom filter (opens in a new tab) استفاده کنید تا به طور مؤثری بررسی کنید که آیا قبل از خواندن فایل هدایت یا پایگاه داده بزرگتر، هدایتی وجود دارد یا خیر.
با در نظر گرفتن مثال قبلی، میتوانید یک فایل فیلتر بلوم تولید شده را به Middleware وارد کنید، سپس بررسی کنید که آیا مسیر نام درخواست ورودی در فیلتر بلوم وجود دارد.
اگر وجود داشته باشد، درخواست را به یک Route Handler ارسال کنید که فایل واقعی را بررسی کرده و کاربر را به URL مناسب هدایت کند. این کار از وارد کردن یک فایل هدایت بزرگ به Middleware جلوگیری میکند که میتواند سرعت هر درخواست ورودی را کاهش دهد.
import { NextResponse, NextRequest } from 'next/server'
import { ScalableBloomFilter } from 'bloom-filters'
import GeneratedBloomFilter from './redirects/bloom-filter.json'
type RedirectEntry = {
destination: string
permanent: boolean
}
// Initialize bloom filter from a generated JSON file
const bloomFilter = ScalableBloomFilter.fromJSON(GeneratedBloomFilter as any)
export async function middleware(request: NextRequest) {
// Get the path for the incoming request
const pathname = request.nextUrl.pathname
// Check if the path is in the bloom filter
if (bloomFilter.has(pathname)) {
// Forward the pathname to the Route Handler
const api = new URL(
`/api/redirects?pathname=${encodeURIComponent(
request.nextUrl.pathname
)}`,
request.nextUrl.origin
)
try {
// Fetch redirect data from the Route Handler
const redirectData = await fetch(api)
if (redirectData.ok) {
const redirectEntry: RedirectEntry | undefined =
await redirectData.json()
if (redirectEntry) {
// Determine the status code
const statusCode = redirectEntry.permanent ? 308 : 307
// Redirect to the destination
return NextResponse.redirect(
redirectEntry.destination,
statusCode
)
}
}
} catch (error) {
console.error(error)
}
}
// No redirect found, continue the request without redirecting
return NextResponse.next()
}سپس، در Route Handler:
import { NextRequest, NextResponse } from 'next/server'
import redirects from '@/app/redirects/redirects.json'
type RedirectEntry = {
destination: string
permanent: boolean
}
export function GET(request: NextRequest) {
const pathname = request.nextUrl.searchParams.get('pathname')
if (!pathname) {
return new Response('Bad Request', { status: 400 })
}
// Get the redirect entry from the redirects.json file
const redirect = (redirects as Record<string, RedirectEntry>)[pathname]
// Account for bloom filter false positives
if (!redirect) {
return new Response('No redirect', { status: 400 })
}
// Return the redirect entry
return NextResponse.json(redirect)
}خوب است بدانید:
- برای تولید یک فیلتر بلوم، میتوانید از کتابخانهای مانند
bloom-filters(opens in a new tab) استفاده کنید.- برای جلوگیری از درخواستهای مخرب، باید درخواستهایی را که به Route Handler شما ارسال میشوند، اعتبارسنجی کنید.