الأدوات الوسطية في Next.js
تُمكِّنك الأدوات أو البرمجيات الوسيطة MiddleWare من تنفيذ مهمة قبل اكتمال كل طلب request ثم بناءً على الطلب الوارد، يمكنك تعديل الرد من خلال إعادة كتابة أو إعادة التوجيه أو إضافة الترويسات أو حتى بالرد على الطلب مباشرة.
تُنفَّذ البرمجيات الوسيطة قبل المحتوى المخزَّن مؤقتًا cached content لذا يمكنك تخصيص الملفات والصفحات الساكنة، وأشهر استخدامات البرمجيات الوسيطة هي في الاستيثاق authentication أو اختبار A/B أو تخصيص الصفحات وفقًا للمناطق الزمنة (عبر بدء استخدام التوجيه عبر i18n) أو في الحماية من الشيفرات الآلية أو غيرها حتى الاستخدامات المتقدمة.
ملاحظة: إن كنت تستخدم البرمجيات الوسيطة قبل الإصدار 12.2، فارجع إلى دليل الترقية.
سجل التغييرات
النسخة | التغييرات |
---|---|
13.1.0 | أضيفت رايات flags متقدمة |
13.0.0 | تستطيع الآن البرمجيات الوسيطة تعديل ترويسات الطلب request headers وترويسات الرد response headers وإرسال الردود |
12.2.0 | استقرار دعم البرمجيات الوسيطة |
12.0.9 | إلزامية استخدام العناوين المطلقة أثناء تشغيل التطبيق بالاستفادة من الحوسبة الحدية Edge |
12.0.0 | دعم البرمجيات الوسطية (تجريبيًا) |
استخدام البرمجيات الوسطية Middleware في Next.js
- ثبّت النسخة الأحدث من Next.js:
npm install next@latest
- أنشئ الملف
middleware.ts
ضمن جذر مجلد مشروعك أو ضمن المجلدsrc
بجوار المجلدpages
. - صدِّر أخيرًا دالة الأداة الوسطية من الملف
middleware.ts
.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
//`await` إن كنت تستخدم `async` يمكن أن تجعل هذه الدالة
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*',
}
المسارات المطابقة
ستُستخدم البرمجيات الوسيطة في كل وجهات مشروعك وفق ترتيب التنفيذ التالي:
headers
منnext.config.js
redirects
منnext.config.js
- مع (
rewrites
وredirects
وغيرها) beforeFiles
(rewrites
) منnext.config.js
- التنقل في نظام المفات (
public/
و_next/static/
و الصفحات وغيرها.) afterFiles
(rewrites
) منnext.config.js
- الوجهات الديناميكية (
/blog/[slug]
) fallback
(rewrites
) منnext.config.js
توجد طريقتين لتعريف المسار الذي تُنفّذ عليه البرمجيات الوسيطة:
- تهيئة مُطابق مخصص custom matchers.
- العبارات الشرطية.
المطابقات
يسمح المطابق matcher
بفلترة البرمجيات الوسيطة لتعمل على مسارات محددة:
export const config = {
matcher: '/about/:path*',
}
يمكنك مطابقة مسار واحد أو عدة مسارات باستخدام المصفوفات:
export const config = {
matcher: ['/about/:path*', '/dashboard/:path*'],
}
يُسمح بالاستخدام الكامل للتعابير النمطية regex عند تهيئة المطابق matcher
مثل أسلوب البحث السلبي قدمًا negative lookahead أو مطابقة المحارف. وكمثال عن البحث السلبي قُدمًا لمطابقة كل المسارات المخصصة المحتملة نجد:
export const config = {
matcher: [
/*
*طابق كل المسارات المطلوبة ما عدا التي تبدأ بـ
* - api (ِAPI وجهات)
* - _next/static (ملفات ساكنة)
* - favicon.ico (favicon الملف)
*/
'/((?!api|_next/static|favicon.ico).*)',
],
}
ملاحظة: يجب أن تكون قيم المطابق ثابتة كي تُحلل بشكل ساكن أثناء بناء التطبيق، وسيجري تجاهل القيم الديناميكية مثل المتغيرات.
لتهيئة المطابقات:
- يجب أن تبدأ بالمحرف
/
. - يمكن أن تضم معاملات مسمّاة مثل
about/:path/
التي قد تطابقabout/a/
وabout/b/
لكن لن تطابقabout/a/c/
. - يمكن أن تضم تغييرات على المعاملات المسمّاة (تبدأ بـ
:
) مثل*about/:path/
الذي يطابقabout/a/b/c/
لأن*
تعني "صفر أو أكثر" و?
"صفر أو واحد" و+
"واحد أو أكثر". - يمكن استخدام التعابير النمطية ضمن أقواس مثل
(*.)/about/
بدلًا منabout/:path/*
.
ملاحظة: لأغراض التوافق تعُدّ 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
تسمح هذه الواجهة بالأمور التالية:
- إعادة توجيه
redirect
الطلب القادم إلى عنوان URL مختلف. - إعادة كتابة
rewrite
(الكتابة فوق) الاستجابة عن طريق عرض عنوان URL محدد. - ضبط ترويسات الطلب لاستخدام وجهات API والدالة
getServerSideProps
والدالةrewrite
لإعادة كتابة الوجهات النهائية. - ضبط ملفات تعريف الارتباط cookies الخاصة بالاستجابة.
- ضبط ترويسات الاستجابة.
لتوليد استجابة عن البرمجيات الوسيطة، عليك تنفيذ على صفحة أو وجهة API حديّة قادرة على توليد استجابة.
استخدام ملفات تعريف الارتباط
تُعد ملفات تعريف الارتباط ترويسات نمطية. إذ تُخزّن هذه الملفات في الترويسة Cookie
الخاصة بالطلب Request
. بينما تخزن ملفات تعريف الارتباط في الترويسة Set-Cookie
في الاستجابة Response
. تزوّدك بطريقة ملائمة للوصول إلى ملفات تعريف الارتباط من خلال الموسِّع cookies
الذي يُستخدم مع NextRequest
و NextResponse
.
- يأتي الموسّع في حالة الطلبات المستقبلة مع التوابع
get
وgetAll
وset
وdelete
، كما يمكنك التحقق من وجود ملف تعريف ارتباط من خلال التابعhas
وإزالته باستخدام التابعclear
. - يأتي الموسِّع في حالة الطلبات المرسلة مع التوابع
get
وgetAll
وset
وdelete
.
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
//ضمن طلب وارد "Cookie:nextjs=fast" افترض ترويسة ملف تعريف ارتباط
//RequestCookies للحصول على ملفات تعريف الارتباط من الطلب باستخدام
const cookie = request.cookies.get('nextjs')?.value
console.log(cookie) // => 'fast'
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
//RequestCookies ضبط ملفات تعريف الارتباط باستخدام
const response = NextResponse.next()
response.cookies.set('vercel', 'fast')
response.cookies.set({
name: 'vercel',
value: 'fast',
path: '/test',
})
const cookie = response.cookies.get('vercel')
console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/test' }
//`Set-Cookie:vercel=fast;path=/test` ستمتلك الاستجابة المرسلة الترويسة
return response
}
ضبط الترويسات
بالإمكان ضبط ترويسات الطلب والاستجابة باستخدام الواجهة البرمجية NextResponse
(ضبط توريسات الطلب متاح في النسخة 13 ومابعد)
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
//`x-hello-from-middleware1` انسخ ترويسات الطلب واضبط ترويسة جديدة
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-hello-from-middleware1', 'hello')
// NextResponse.rewrite يمكن ضبط ترويسات الطلب أيضًا باستخدام
const response = NextResponse.next({
request: {
// ترويسات للطلب الجديد
headers: requestHeaders,
},
})
//`x-hello-from-middleware2` ضبط ترويسة استجابة جديدة
response.headers.set('x-hello-from-middleware2', 'hello')
return response
}
ملاحظة: تحاشى ضبط ترويسات كبيرة الحجم لانها قد تسبب الخطأ "431 Request Header Fields Too Large" تبعًا لإعدادات الواجهة الخلفية للتطبيق على خادم الويب.
توليد استجابة في Next.js
يمكنك الاستجابة للبرمجيات الوسيطة مباشرة بإعادة الكائن NextResponse
(متاحة ابتداءً من النسخة 13). وعند تمكين هذه الميزة، ستتمكن من الحصول على استجابة من البرمجيات الوسيطة باستخدم الواجهتين Response
أو NextResponse
.
// middleware.ts
import { NextRequest, NextResponse } from 'next/server'
import { isAuthenticated } from '@lib/auth'
// `/api/` حصر استخام البرمجيات الوسيطة بالمسارات التي تبدأ بـ
export const config = {
matcher: '/api/:function*',
}
export function middleware(request: NextRequest) {
//طلب الاستيثاق للتحقق من الطلب
if (!isAuthenticated(request)) {
//للإشارة إلى خطأالاستيثاق JSON الاستجابة باستخدام
return new NextResponse(
JSON.stringify({ success: false, message: 'authentication failed' }),
{ status: 401, headers: { 'content-type': 'application/json' } }
)
}
}
رايات متقدمة للبرمجات الوسيطة
أضيفت رايتان جديدتان إلى البرمجيات الوسيطة في النسخة 13.1 من Next.js هما :skipMiddlewareUrlNormalize
و skipTrailingSlashRedirect
، وذلك للتعامل مع بعض الحالات المتقدمة.
تتيح الراية skipTrailingSlashRedirect
إيقاف التوجيه الافتراضي في Next.js لإضافة أو إزالة المحارف /
السابقة للوجهة من أجل تخصيص طريقة العمل معها داخل البرمجيات الوسيطة التي تسمح بإبقاء تلك المحارف لبعض المسارات فقط لتسهيل عملية التهجير التدريجي incremental migrations.
// 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
تعطيل عملية اختصار عناوين URL التي تنفذها Next.js كي تتعامل مع عناوين الزيارات المباشرة أو العناوين عند التنقل في طرف العميل. إذ تحتاج في بعض الحالات المتقدمة تحكمًا كاملًا باستخدام عنوان URL الأصلية التي تتيح هذه الراية استخدامها.
// next.config.js
module.exports = {
skipMiddlewareUrlNormalize: true,
}
// middleware.js
export default async function middleware(req) {
const { pathname } = req.nextUrl
// /_next/data/build-id/hello.json الحصول على
console.log(pathname)
// /_next/data/build-id/hello.json تصبح مع الراية على الشكل
// /hello بينما ستكون دون هذه الراية على الشكل
}
اقرأ أيضًا
- الواجهة البرمجية التي تَستخدمها الأداة الوسطية.
- واجهات ويب البرمجية التي تدعم بيئة التشغيل الحدية.
- قياس الأداء في تطبيقات Next.js.
المصادر
- الصفحة middleware من توثيق Next.js الرسمي.