الفرق بين المراجعتين لصفحة: «Next.js/middleware»

من موسوعة حسوب
لا ملخص تعديل
طلا ملخص تعديل
 
(5 مراجعات متوسطة بواسطة مستخدمين اثنين آخرين غير معروضة)
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE:الأدوات الوسطية في Next.js}}</noinclude>
<noinclude>{{DISPLAYTITLE:الأدوات الوسطية في Next.js}}</noinclude>
تُمكِّنك الأدوات الوسيطة MiddleWare من استخدام الشيفرة لتعديل الإعدادات، وهذا ما يمنحك مرونة كاملة في Next.js نظرًا للقدرة على تنفيذ الشيفرة قبل أن يكتمل الطلب.
تُمكِّنك الأدوات أو البرمجيات الوسيطة MiddleWare من تنفيذ مهمة قبل اكتمال كل طلب request ثم بناءً على الطلب الوارد، يمكنك تعديل الرد من خلال إعادة كتابة أو إعادة التوجيه أو إضافة الترويسات أو حتى بالرد على الطلب مباشرة.
 
تُنفَّذ البرمجيات الوسيطة '''قبل''' المحتوى المخزَّن مؤقتًا cached content لذا يمكنك تخصيص الملفات والصفحات الساكنة، وأشهر استخدامات البرمجيات الوسيطة هي في الاستيثاق authentication أو اختبار A/B أو تخصيص الصفحات وفقًا للمناطق الزمنة (عبر بدء استخدام [[Next.js/i18n routing|التوجيه عبر i18n]]) أو في الحماية من الشيفرات الآلية أو غيرها حتى الاستخدامات المتقدمة.
 
'''ملاحظة''': إن كنت تستخدم البرمجيات الوسيطة قبل الإصدار 12.2، فارجع إلى [https://nextjs.org/docs/messages/middleware-upgrade-guide دليل الترقية].
 
== سجل التغييرات ==
{| class="wikitable"
{| class="wikitable"
|+
!النسخة
!النسخة
!التغييرات
!التغييرات
|-
|13.1.0
|أضيفت رايات flags متقدمة
|-
|13.0.0
|تستطيع الآن البرمجيات الوسيطة تعديل ترويسات الطلب request headers وترويسات الرد response headers وإرسال الردود
|-
|12.2.0
|استقرار دعم البرمجيات الوسيطة
|-
|-
|12.0.9
|12.0.9
|إلزامية استخدام عناوين المطلقة أثناء تشغيل التطبيق بالاستفادة من الحوسبة الحدية Edge
|إلزامية استخدام العناوين المطلقة أثناء تشغيل التطبيق بالاستفادة من الحوسبة الحدية Edge
|-
|-
|12.0.0
|12.0.0
|دعم الأدوات الوسطية (تجريبيًا)
|دعم البرمجيات الوسطية (تجريبيًا)
|}
|}
وفقًا للطلب الذي يرسله المستخدم، ستتمكن من تعديل الاستجابة من خلال إعادة كتابة أو إعادة التوجيه أو إضافة الترويسات أو حتى بالتصيير الآني لمحتوى HTML.
== استخدام البرمجيات الوسطية Middleware ==
ثبّت النسخة الأحدث من Next.js:<syntaxhighlight lang="bash">
npm install next@latest
</syntaxhighlight>أنشئ الملف <code>middleware.ts</code> ضمن جذر مجلد مشروعك أو ضمن المجلد <code>src</code> بجوار المجلد <code>pages</code> ثم صدِّر دالة الأداة الوسطية من الملف  <code>middleware.ts</code>.<syntaxhighlight lang="javascript">
// 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*',
}
</syntaxhighlight>
== المسارات المطابقة ==
ستُستخدم البرمجيات الوسيطة في كل وجهات مشروعك وفق ترتيب التنفيذ التالي:
 
# <code>headers</code> من <code>next.config.js</code>
# <code>redirects</code> من <code>next.config.js</code>
# مع (<code>rewrites</code> و <code>redirects</code> وغيرها)
# <code>beforeFiles</code> (<code>rewrites</code>) من <code>next.config.js</code>
# التنقل في نظام المفات (<code>public/</code> و ‎<code>_next/static/‎</code>و الصفحات وغيرها.)
# <code>afterFiles</code> (<code>rewrites</code>) من <code>next.config.js</code>
# الوجهات الديناميكية (‎<code>/blog/[slug]</code>)
# <code>fallback</code> (<code>rewrites</code>) من <code>next.config.js</code>
 
توجد طريقتين لتعريف المسار الذي تُنفّذ عليه البرمجيات الوسيطة:
 
# تهيئة مُطابق مخصص custom matchers.
# العبارات الشرطية.
 
=== المطابقات ===
يسمح المطابق <code>matcher</code> بفلترة البرمجيات الوسيطة لتعمل على مسارات محددة:<syntaxhighlight lang="javascript">
export const config = {
  matcher: '/about/:path*',
}
</syntaxhighlight>يمكنك مطابقة مسار واحد أو عدة مسارات باستخدام المصفوفات: <syntaxhighlight lang="javascript">
export const config = {
  matcher: ['/about/:path*', '/dashboard/:path*'],
}
</syntaxhighlight>يُسمح بالاستخدام الكامل للتعابير النمطية regex عند تهيئة المطابق <code>matcher</code>  مثل أسلوب البحث السلبي قدمًا negative lookahead أو مطابقة المحارف. وكمثال عن البحث السلبي قُدمًا لمطابقة كل المسارات المخصصة المحتملة نجد:<syntaxhighlight lang="javascript">
export const config = {
  matcher: [
    /*
    *طابق كل المسارات المطلوبة ما عدا التي تبدأ بـ
    * - api (ِAPI وجهات)
    * - _next/static (ملفات ساكنة)
    * - favicon.ico (favicon الملف)
    */
    '/((?!api|_next/static|favicon.ico).*)',
  ],
}
</syntaxhighlight><blockquote>'''ملاحظة''': يجب أن تكون قيم المطابق ثابتة كي تُحلل بشكل ساكن أثناء بناء التطبيق، وسيجري تجاهل القيم الديناميكية مثل المتغيرات.</blockquote>لتهيئة المطابقات:
 
# يجب أن تبدأ بالمحرف <code>/</code>.
# يمكن أن تضم معاملات مسمّاة مثل <code>about/:path/</code>  التي قد تطابق <code>about/a/</code> و <code>about/b/</code>  لكن لن تطابق <code>about/a/c/</code>.
# يمكن أن تضم تغييرات على المعاملات المسمّاة (تبدأ بـ <code>:</code>) مثل  <code>*about/:path/</code> الذي يطابق  <code>about/a/b/c/</code> لأن <code>*</code> تعني "صفر أو أكثر" و <code>?</code> "صفر أو واحد" و <code>+</code> "واحد أو أكثر".
# يمكن استخدام التعابير النمطية ضمن أقواس مثل <code>(*.)/about/</code> بدلًا من  <code>about/:path/*</code>.
 
<blockquote>'''ملاحظة''': لأغراض التوافق تعُدّ Next.js المسار  <code>public/</code>  هو نفسه <code>public/index/</code> وبالتالي سيعثر عليه المُطابق  <code>public/:path/</code>.</blockquote>
 
=== العبارات الشرطية ===
<syntaxhighlight lang="javascript">
// middleware.ts
 
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'


== استخدامات الأدوات الوسطية في Next.js ==
export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname.startsWith('/about')) {
    return NextResponse.rewrite(new URL('/about-2', request.url))
  }


* ثبّت النسخة الحدث من Next.js:
  if (request.nextUrl.pathname.startsWith('/dashboard')) {
<syntaxhighlight lang="bash">
    return NextResponse.rewrite(new URL('/dashboard/user', request.url))
npm install next@latest
  }
}
</syntaxhighlight>
</syntaxhighlight>


* أنشئ الملف <code>middleware.ts_</code> ضمن المجلد <code>pages/</code>.
== الواجهة البرمجية NextResponse ==
* صدِّر أخيرًا دالة الأداة الوسطية من الملف  <code>middleware.ts_</code>.
تسمح هذه الواجهة بالأمور التالية:
 
* إعادة توجيه <code>redirect</code> الطلب القادم إلى عنوان URL مختلف.
* إعادة كتابة <code>rewrite</code> (الكتابة فوق) الاستجابة عن طريق عرض عنوان URL محدد.
* ضبط ترويسات الطلب لاستخدام وجهات API والدالة <code>getServerSideProps</code> والدالة <code>rewrite</code> لإعادة كتابة الوجهات النهائية.
* ضبط ملفات تعريف الارتباط cookies الخاصة بالاستجابة.
* ضبط ترويسات الاستجابة.
 
لتوليد استجابة عن البرمجيات الوسيطة، عليك تنفيذ على [[Next.js/pages|صفحة]] أو وجهة API حديّة قادرة على توليد استجابة.
 
== استخدام ملفات تعريف الارتباط ==
تُعد ملفات تعريف الارتباط ترويسات نمطية. إذ تُخزّن هذه الملفات في الترويسة <code>Cookie</code>  الخاصة بالطلب <code>Request</code>. بينما تخزن ملفات تعريف الارتباط في الترويسة <code>Set-Cookie</code> في الاستجابة <code>Response</code>. تزوّدك بطريقة ملائمة للوصول إلى ملفات تعريف الارتباط من خلال الموسِّع <code>cookies</code> الذي يُستخدم مع <code>NextRequest</code> و <code>NextResponse</code>.
 
# يأتي الموسّع في حالة الطلبات المستقبلة مع التوابع <code>get</code> و <code>getAll</code> و <code>set</code> و <code>delete</code>، كما يمكنك التحقق من وجود ملف تعريف ارتباط من خلال التابع <code>has</code> وإزالته باستخدام التابع <code>clear</code>.
# يأتي الموسِّع في حالة الطلبات المرسلة مع التوابع <code>get</code> و <code>getAll</code> و <code>set</code> و <code>delete</code>.
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
// pages/_middleware.ts
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'


import type { NextFetchEvent, 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' }]


export function middleware(req: NextRequest, ev: NextFetchEvent) {
  request.cookies.has('nextjs') // => true
   return new Response('Hello, world!')
  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
}
}
</syntaxhighlight>'''تنويه''': استخدمنا في هذا المثال واجهة ويب البرمجية المعيارية للاستجابة [https://developer.mozilla.org/en-US/docs/Web/API/Response Web API Response].
</syntaxhighlight>


== الواجهة البرمجية ==
== ضبط الترويسات ==
تتشكل الأدوات الوسطية من خلال الدالة الموجودة في الملف، وتعتمد واجهتها البرمجية على الكائنات الأصلية التالية: <code>FetchEvent</code> و <code>Response</code> و <code>Request</code>. وقد وُسِّعت هذه الكائنات لتعطيك تحكمًا أفضل بطريقة التعامل مع الاستجابة وتهيئتها وفقًا للطلب الوارد من المستخدم.
بالإمكان ضبط ترويسات الطلب والاستجابة باستخدام الواجهة البرمجية <code>NextResponse</code> (ضبط توريسات الطلب متاح في النسخة 13 ومابعد):<syntaxhighlight lang="javascript">
// middleware.ts


ستكون بصمة الدالة كالتالي:<syntaxhighlight lang="javascript">
import { NextResponse } from 'next/server'
import type { NextFetchEvent } from 'next/server'
import type { NextRequest } from 'next/server'
import type { NextRequest } from 'next/server'


export type Middleware = (
export function middleware(request: NextRequest) {
   request: NextRequest,
  //`x-hello-from-middleware1` انسخ ترويسات الطلب واضبط ترويسة جديدة
   event: NextFetchEvent
  const requestHeaders = new Headers(request.headers)
) => Promise<Response | undefined> | Response | undefined
   requestHeaders.set('x-hello-from-middleware1', 'hello')
</syntaxhighlight>بإمكانك تصدير الدالة افتراضيًا ولا حاجة لتسميتها <code>middleware</code>، مع أن ذلك أمر تقليدي. ولا حاجة أيضًا أن تكون الدالة غير متزامنة <code>async</code> إلا إن أردتها أن تنفِّذ شيفرة غير متزامنة.  
 
  // NextResponse.rewrite يمكن ضبط ترويسات الطلب أيضًا باستخدام 
  const response = NextResponse.next({
    request: {
      // ترويسات للطلب الجديد
      headers: requestHeaders,
    },
  })
 
  //`x-hello-from-middleware2` ضبط ترويسة استجابة جديدة
  response.headers.set('x-hello-from-middleware2', 'hello')
   return response
}
</syntaxhighlight><blockquote>'''ملاحظة''': تحاشى ضبط ترويسات كبيرة الحجم لانها قد تسبب الخطأ "[https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/431 431 Request Header Fields Too Large]" تبعًا لإعدادات الواجهة الخلفية للتطبيق على خادم الويب.</blockquote>
 
== توليد استجابة في Next.js ==
يمكنك الاستجابة للبرمجيات الوسيطة مباشرة بإعادة الكائن <code>NextResponse</code> (متاحة ابتداءً من النسخة 13). وعند تمكين هذه الميزة، ستتمكن من الحصول على استجابة من البرمجيات الوسيطة  باستخدم الواجهتين <code>Response</code> أو <code>NextResponse</code>.<syntaxhighlight lang="javascript">
// 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' } }
    )
  }
}
</syntaxhighlight>
 
== رايات متقدمة للبرمجات الوسيطة ==
أضيفت رايتان جديدتان إلى البرمجيات الوسيطة في النسخة 13.1 من Next.js هما :<code>skipMiddlewareUrlNormalize</code> و <code>skipTrailingSlashRedirect</code>، وذلك للتعامل مع بعض الحالات المتقدمة.


لمعلومات أكثر، اطلع على [[Next.js/next server|توثيق الواجهة البرمجية للأداة الوسطية في Next.js]].
تتيح الراية <code>skipTrailingSlashRedirect</code> إيقاف التوجيه الافتراضي في Next.js لإضافة أو إزالة المحارف <code>/</code> السابقة للوجهة من أجل تخصيص طريقة العمل معها داخل البرمجيات الوسيطة التي تسمح بإبقاء تلك المحارف لبعض المسارات فقط لتسهيل عملية التهجير التدريجي incremental migrations.<syntaxhighlight lang="javascript">
// next.config.js
module.exports = {
  skipTrailingSlashRedirect: true,
}
// middleware.js


== أمثلة عن حالات استخدام Next.js ==
const legacyPrefixes = ['/docs', '/blog']
تُستخدم الأداة الوسطية غالبًا في الحالات التي تشترك فيها مجموعة من الصفحات في منطق برمجي معين مثل:


* الاستيثاق.
export default async function middleware(req) {
* الحماية من الشيفرات الآلية.
  const { pathname } = req.nextUrl
* إعادة التوجيه والكتابة.
* التعامل مع المتصفحات غير المدعومة.
* الرايات المستقبلية والاختبارات ثنائية الخيار A/B tests.
* متطلبات التوجه المتقد من خلال i18n.


بإمكانك الاطلاع على [https://github.com/vercel/examples/tree/main/edge-functions أمثلة عن حالات الاستخدام السابقة] على GitHub
  if (legacyPrefixes.some((prefix) => pathname.startsWith(prefix))) {
    return NextResponse.next()
  }


== ترتيب التنفيذ ==
  // apply trailing slash handling
إن أنشأت الأداة الوسطية في المجلد <code>pages/_middleware.ts/</code>، ستُنفَّذ مع جميع الوجهات الموجودة في هذا المجلد. يفترض المثال التالي وجود وجهتين هما <code>about.tsx</code> و <code>teams.tsx</code>:<syntaxhighlight lang="bash">
  if (
- package.json
    !pathname.endsWith('/') &&
- /pages
    !pathname.match(/((?!\.well-known(?:\/.*)?)(?:[^/]+\/)*[^/]+\.\w+)/)
     _middleware.ts # pages ستُنفَّذ كل الوجهات في المجلد
  ) {
    index.tsx
    req.nextUrl.pathname += '/'
    about.tsx
     return NextResponse.redirect(req.nextUrl)
    teams.tsx
  }
</syntaxhighlight>إن وجدت مجلدات فرعية متداخله مع الوجهات، فستُنفَّذ الأداة الوسطية من الأعلى للأسفل. لنفترض مثلًا وجود الأداتين  <code>/pages/about/_middleware.ts</code> و <code>/pages/about/team/_middleware.ts</code>، فستُنفّذ الأدلة الموجودة في <code>/about</code> أولًا. يظهر المثال التالي تنفيذ الأداة الوسطية في الوجهات المتداخلة:<syntaxhighlight lang="bash">
}
- package.json
</syntaxhighlight>بينما تتيح الراية <code>skipMiddlewareUrlNormalize</code> تعطيل عملية اختصار عناوين URL التي تنفذها Next.js كي تتعامل مع عناوين الزيارات المباشرة أو العناوين عند التنقل في طرف العميل. إذ تحتاج في بعض الحالات المتقدمة تحكمًا كاملًا باستخدام عنوان URL الأصلية التي تتيح هذه الراية استخدامها.<syntaxhighlight lang="javascript">
- /pages
// next.config.js
    index.tsx
 
    - /about
module.exports = {
      _middleware.ts # تُنفّذ أولًا
  skipMiddlewareUrlNormalize: true,
      about.tsx
}
      - /teams
// middleware.js
        _middleware.ts # تُنفَّذ ثانيًا
        teams.tsx
</syntaxhighlight>تُنفّذ الأداة الوسطية مباشرة بعد التوجيهات <code>redirects</code> والترويسات <code>headers</code> وقبل أول عملية بحث لنظام الملفات. يستثني ذلك ملفات المجلد <code>next_/</code>.


== نشر التطبيقات التي تضم أدوات وسطية ==
export default async function middleware(req) {
تستخدم الأدوات الوسطية بيئة تشغيل مقيّدة تدعم واجهات ويب البرمجية المعيارية مثل <code>fetch</code>. يعمل ذلك جيدًا مع <code>next start</code> وعلى منصات الحوسبة الحدية مثل Vercel الذي يستخدم الدوال الحدية [http://www.vercel.com/edge Edge Functions].
  const { pathname } = req.nextUrl


== المصادر ==
  // /_next/data/build-id/hello.json الحصول على 


* الصفحة middleware(beta) من توثيق Next.js الرسمي.
  console.log(pathname)
  // /_next/data/build-id/hello.json تصبح مع الراية على الشكل 
  // /hello بينما ستكون دون هذه الراية على الشكل
}
</syntaxhighlight>


== اقرأ أيضًا ==
== اقرأ أيضًا ==


* [[Next.js/next server|الواجهة البرمجية التي تُستخدمها الأداة الوسطية]].
* [[Next.js/next server|الواجهة البرمجية التي تَستخدمها الأداة الوسطية]].
* [[Next.js/edge runtime|واجهات ويب البرمجية التي تدعم بيئة التشغيل الحدية]].
* [[Next.js/edge runtime|واجهات ويب البرمجية التي تدعم بيئة التشغيل الحدية]].
* [[Next.js/measuring performance|قياس الأداء في تطبيقات Next.js]].
* [[Next.js/measuring performance|قياس الأداء في تطبيقات Next.js]].
== المصادر ==
* الصفحة [https://nextjs.org/docs/advanced-features/middleware middleware] من توثيق Next.js الرسمي.
[[تصنيف:Next.js|{{SUBPAGENAME}}]]
[[تصنيف:Next.js Advanced Features|{{SUBPAGENAME}}]]

المراجعة الحالية بتاريخ 16:10، 4 فبراير 2023

تُمكِّنك الأدوات أو البرمجيات الوسيطة 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:

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*',
}

المسارات المطابقة

ستُستخدم البرمجيات الوسيطة في كل وجهات مشروعك وفق ترتيب التنفيذ التالي:

  1. headers من next.config.js
  2. redirects من next.config.js
  3. مع (rewrites و redirects وغيرها)
  4. beforeFiles (rewrites) من next.config.js
  5. التنقل في نظام المفات (public/ و ‎_next/static/‎و الصفحات وغيرها.)
  6. afterFiles (rewrites) من next.config.js
  7. الوجهات الديناميكية (‎/blog/[slug])
  8. fallback (rewrites) من next.config.js

توجد طريقتين لتعريف المسار الذي تُنفّذ عليه البرمجيات الوسيطة:

  1. تهيئة مُطابق مخصص custom matchers.
  2. العبارات الشرطية.

المطابقات

يسمح المطابق 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).*)',
  ],
}

ملاحظة: يجب أن تكون قيم المطابق ثابتة كي تُحلل بشكل ساكن أثناء بناء التطبيق، وسيجري تجاهل القيم الديناميكية مثل المتغيرات.

لتهيئة المطابقات:

  1. يجب أن تبدأ بالمحرف /.
  2. يمكن أن تضم معاملات مسمّاة مثل about/:path/ التي قد تطابق about/a/ و about/b/ لكن لن تطابق about/a/c/.
  3. يمكن أن تضم تغييرات على المعاملات المسمّاة (تبدأ بـ :) مثل *about/:path/ الذي يطابق about/a/b/c/ لأن * تعني "صفر أو أكثر" و ? "صفر أو واحد" و + "واحد أو أكثر".
  4. يمكن استخدام التعابير النمطية ضمن أقواس مثل (*.)/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.

  1. يأتي الموسّع في حالة الطلبات المستقبلة مع التوابع get و getAll و set و delete، كما يمكنك التحقق من وجود ملف تعريف ارتباط من خلال التابع has وإزالته باستخدام التابع clear.
  2. يأتي الموسِّع في حالة الطلبات المرسلة مع التوابع 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 بينما ستكون دون هذه الراية على الشكل 
}

اقرأ أيضًا

المصادر

  • الصفحة middleware من توثيق Next.js الرسمي.