إعادة التوجيه
هناك عدة طرق يمكنك من خلالها التعامل مع عمليات إعادة التوجيه في Next.js. ستغطي هذه الصفحة كل خيار متاح، حالات الاستخدام، وكيفية إدارة أعداد كبيرة من عمليات إعادة التوجيه.
API | الغرض | المكان | رمز الحالة |
---|---|---|---|
useRouter | تنفيذ تنقل من جانب العميل | المكونات | غير متاح |
redirects في next.config.js | إعادة توجيه طلب وارد بناءً على مسار | ملف next.config.js | 307 (مؤقت) أو 308 (دائم) |
NextResponse.redirect | إعادة توجيه طلب وارد بناءً على شرط | Middleware | أي |
خطاف useRouter()
إذا كنت بحاجة إلى إعادة التوجيه داخل مكون، يمكنك استخدام طريقة push
من خطاف useRouter
. على سبيل المثال:
import { useRouter } from 'next/router'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
لوحة التحكم
</button>
)
}
import { useRouter } from 'next/router'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
لوحة التحكم
</button>
)
}
معلومة مفيدة:
- إذا لم تكن بحاجة إلى تنقل المستخدم برمجيًا، يجب استخدام مكون
<Link>
.
راجع مرجع API لـ useRouter
لمزيد من المعلومات.
redirects
في next.config.js
خيار redirects
في ملف next.config.js
يسمح لك بإعادة توجيه مسار طلب وارد إلى مسار وجهة مختلف. هذا مفيد عندما تقوم بتغيير هيكل عناوين URL للصفحات أو لديك قائمة بعمليات إعادة التوجيه معروفة مسبقًا.
يدعم redirects
مطابقة المسار، مطابقة الرأس، الكوكيز، والاستعلام، مما يمنحك المرونة لإعادة توجيه المستخدمين بناءً على طلب وارد.
لاستخدام redirects
، أضف الخيار إلى ملف next.config.js
:
module.exports = {
async redirects() {
return [
// إعادة توجيه أساسية
{
source: '/about',
destination: '/',
permanent: true,
},
// مطابقة مسار باستخدام أحرف البدل
{
source: '/blog/:slug',
destination: '/news/:slug',
permanent: true,
},
]
},
}
راجع مرجع API لـ redirects
لمزيد من المعلومات.
معلومة مفيدة:
- يمكن أن تُرجع
redirects
رمز حالة 307 (إعادة توجيه مؤقتة) أو 308 (إعادة توجيه دائمة) مع خيارpermanent
.- قد يكون لـ
redirects
حد على بعض المنصات. على سبيل المثال، في Vercel، هناك حد لـ 1,024 إعادة توجيه. لإدارة عدد كبير من عمليات إعادة التوجيه (1000+)، فكر في إنشاء حل مخصص باستخدام Middleware. راجع إدارة عمليات إعادة التوجيه على نطاق واسع للمزيد.- تعمل
redirects
قبل Middleware.
NextResponse.redirect
في Middleware
يسمح لك Middleware بتشغيل التعليمات البرمجية قبل اكتمال الطلب. ثم، بناءً على الطلب الوارد، يمكنك إعادة التوجيه إلى عنوان URL مختلف باستخدام NextResponse.redirect
. هذا مفيد إذا كنت ترغب في إعادة توجيه المستخدمين بناءً على شرط (مثل المصادقة، إدارة الجلسة، إلخ) أو لديك عدد كبير من عمليات إعادة التوجيه.
على سبيل المثال، لإعادة توجيه المستخدم إلى صفحة /login
إذا لم يكن مصادقًا:
import { NextResponse, NextRequest } from 'next/server'
import { authenticate } from 'auth-provider'
export function middleware(request: NextRequest) {
const isAuthenticated = authenticate(request)
// إذا كان المستخدم مصادقًا، تابع كالمعتاد
if (isAuthenticated) {
return NextResponse.next()
}
// إعادة التوجيه إلى صفحة تسجيل الدخول إذا لم يكن مصادقًا
return NextResponse.redirect(new URL('/login', request.url))
}
export const config = {
matcher: '/dashboard/:path*',
}
import { NextResponse } from 'next/server'
import { authenticate } from 'auth-provider'
export function middleware(request) {
const isAuthenticated = authenticate(request)
// إذا كان المستخدم مصادقًا، تابع كالمعتاد
if (isAuthenticated) {
return NextResponse.next()
}
// إعادة التوجيه إلى صفحة تسجيل الدخول إذا لم يكن مصادقًا
return NextResponse.redirect(new URL('/login', request.url))
}
export const config = {
matcher: '/dashboard/:path*',
}
معلومة مفيدة:
- يعمل Middleware بعد
redirects
فيnext.config.js
وقبل التصيير.
راجع وثائق Middleware لمزيد من المعلومات.
إدارة عمليات إعادة التوجيه على نطاق واسع (متقدم)
لإدارة عدد كبير من عمليات إعادة التوجيه (1000+)، قد تفكر في إنشاء حل مخصص باستخدام Middleware. هذا يسمح لك بالتعامل مع عمليات إعادة التوجيه برمجيًا دون الحاجة إلى إعادة نشر تطبيقك.
للقيام بذلك، ستحتاج إلى النظر في:
- إنشاء وتخزين خريطة إعادة توجيه.
- تحسين أداء البحث عن البيانات.
مثال Next.js: راجع مثالنا Middleware مع مرشح Bloom لتنفيذ التوصيات أدناه.
1. إنشاء وتخزين خريطة إعادة توجيه
خريطة إعادة التوجيه هي قائمة بعمليات إعادة التوجيه التي يمكنك تخزينها في قاعدة بيانات (عادةً مخزن مفتاح-قيمة) أو ملف JSON.
ضع في الاعتبار هيكل البيانات التالي:
{
"/old": {
"destination": "/new",
"permanent": true
},
"/blog/post-old": {
"destination": "/blog/post-new",
"permanent": true
}
}
في Middleware، يمكنك القراءة من قاعدة بيانات مثل Edge Config من Vercel أو Redis، وإعادة توجيه المستخدم بناءً على الطلب الوارد:
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)
}
// لم يتم العثور على إعادة توجيه، تابع بدون إعادة توجيه
return NextResponse.next()
}
import { NextResponse } from 'next/server'
import { get } from '@vercel/edge-config'
export async function middleware(request) {
const pathname = request.nextUrl.pathname
const redirectData = await get(pathname)
if (redirectData) {
const redirectEntry = JSON.parse(redirectData)
const statusCode = redirectEntry.permanent ? 308 : 307
return NextResponse.redirect(redirectEntry.destination, statusCode)
}
// لم يتم العثور على إعادة توجيه، تابع بدون إعادة توجيه
return NextResponse.next()
}
2. تحسين أداء البحث عن البيانات
قراءة مجموعة بيانات كبيرة لكل طلب وارد يمكن أن تكون بطيئة ومكلفة. هناك طريقتان لتحسين أداء البحث عن البيانات:
- استخدام قاعدة بيانات مُحسنة للقراءة السريعة، مثل Vercel Edge Config أو Redis.
- استخدام استراتيجية بحث عن البيانات مثل مرشح بلوم (Bloom filter) للتحقق بكفاءة مما إذا كان هناك إعادة توجيه قبل قراءة ملف أو قاعدة بيانات إعادة التوجيه الأكبر.
بالنظر إلى المثال السابق، يمكنك استيراد ملف مرشح بلوم مُنشأ إلى Middleware، ثم التحقق مما إذا كان مسار الطلب الوارد موجودًا في مرشح بلوم.
إذا كان موجودًا، يتم توجيه الطلب إلى مسارات API (API Routes) والذي سيتحقق من الملف الفعلي ويقوم بإعادة توجيه المستخدم إلى العنوان المناسب. هذا يتجنب استيراد ملف إعادة توجيه كبير إلى 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
}
// تهيئة مرشح بلوم من ملف JSON مُنشأ
const bloomFilter = ScalableBloomFilter.fromJSON(GeneratedBloomFilter as any)
export async function middleware(request: NextRequest) {
// الحصول على مسار الطلب الوارد
const pathname = request.nextUrl.pathname
// التحقق مما إذا كان المسار موجودًا في مرشح بلوم
if (bloomFilter.has(pathname)) {
// توجيه مسار الطلب إلى معالج المسار
const api = new URL(
`/api/redirects?pathname=${encodeURIComponent(request.nextUrl.pathname)}`,
request.nextUrl.origin
)
try {
// جلب بيانات إعادة التوجيه من معالج المسار
const redirectData = await fetch(api)
if (redirectData.ok) {
const redirectEntry: RedirectEntry | undefined =
await redirectData.json()
if (redirectEntry) {
// تحديد رمز الحالة
const statusCode = redirectEntry.permanent ? 308 : 307
// إعادة التوجيه إلى الوجهة
return NextResponse.redirect(redirectEntry.destination, statusCode)
}
}
} catch (error) {
console.error(error)
}
}
// لم يتم العثور على إعادة توجيه، متابعة الطلب دون إعادة توجيه
return NextResponse.next()
}
import { NextResponse } from 'next/server'
import { ScalableBloomFilter } from 'bloom-filters'
import GeneratedBloomFilter from './redirects/bloom-filter.json'
// تهيئة مرشح بلوم من ملف JSON مُنشأ
const bloomFilter = ScalableBloomFilter.fromJSON(GeneratedBloomFilter)
export async function middleware(request) {
// الحصول على مسار الطلب الوارد
const pathname = request.nextUrl.pathname
// التحقق مما إذا كان المسار موجودًا في مرشح بلوم
if (bloomFilter.has(pathname)) {
// توجيه مسار الطلب إلى معالج المسار
const api = new URL(
`/api/redirects?pathname=${encodeURIComponent(request.nextUrl.pathname)}`,
request.nextUrl.origin
)
try {
// جلب بيانات إعادة التوجيه من معالج المسار
const redirectData = await fetch(api)
if (redirectData.ok) {
const redirectEntry = await redirectData.json()
if (redirectEntry) {
// تحديد رمز الحالة
const statusCode = redirectEntry.permanent ? 308 : 307
// إعادة التوجيه إلى الوجهة
return NextResponse.redirect(redirectEntry.destination, statusCode)
}
}
} catch (error) {
console.error(error)
}
}
// لم يتم العثور على إعادة توجيه، متابعة الطلب دون إعادة توجيه
return NextResponse.next()
}
ثم، في مسار API:
import { NextApiRequest, NextApiResponse } from 'next'
import redirects from '@/app/redirects/redirects.json'
type RedirectEntry = {
destination: string
permanent: boolean
}
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const pathname = req.query.pathname
if (!pathname) {
return res.status(400).json({ message: 'Bad Request' })
}
// الحصول على إدخال إعادة التوجيه من ملف redirects.json
const redirect = (redirects as Record<string, RedirectEntry>)[pathname]
// حساب النتائج الإيجابية الخاطئة لمرشح بلوم
if (!redirect) {
return res.status(400).json({ message: 'No redirect' })
}
// إرجاع إدخال إعادة التوجيه
return res.json(redirect)
}
import redirects from '@/app/redirects/redirects.json'
export default function handler(req, res) {
const pathname = req.query.pathname
if (!pathname) {
return res.status(400).json({ message: 'Bad Request' })
}
// الحصول على إدخال إعادة التوجيه من ملف redirects.json
const redirect = redirects[pathname]
// حساب النتائج الإيجابية الخاطئة لمرشح بلوم
if (!redirect) {
return res.status(400).json({ message: 'No redirect' })
}
// إرجاع إدخال إعادة التوجيه
return res.json(redirect)
}
جيد أن تعرف:
- لإنشاء مرشح بلوم، يمكنك استخدام مكتبة مثل
bloom-filters
.- يجب التحقق من صحة الطلبات المرسلة إلى معالج المسار لمنع الطلبات الضارة.