إعادة التوجيه (rewrites)

تسمح لك إعادة التوجيه (rewrites) بتعيين مسار طلب وارد إلى مسار وجهة مختلف.

تعمل إعادة التوجيه كوكيل URL وتخفي مسار الوجهة، مما يجعلها تبدو وكأن المستخدم لم يغير موقعه على الموقع. على النقيض من ذلك، فإن عمليات إعادة التوجيه (redirects) ستوجه إلى صفحة جديدة وتظهر تغييرات URL.

لاستخدام إعادة التوجيه، يمكنك استخدام مفتاح rewrites في next.config.js:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/about',
        destination: '/',
      },
    ]
  },
}

يتم تطبيق إعادة التوجيه على توجيه العميل، حيث سيتم تطبيق إعادة التوجيه على <Link href="/about"> في المثال أعلاه.

rewrites هي دالة غير متزامنة تتوقع إرجاع مصفوفة أو كائن من المصفوفات (انظر أدناه) يحتوي على كائنات بخصائص source و destination:

  • source: String - هو نمط مسار الطلب الوارد.
  • destination: String - المسار الذي تريد التوجيه إليه.
  • basePath: false أو undefined - إذا كانت false فلن يتم تضمين basePath عند المطابقة، يمكن استخدامها لإعادة التوجيه الخارجية فقط.
  • locale: false أو undefined - ما إذا كان يجب عدم تضمين اللغة عند المطابقة.
  • has هي مصفوفة من كائنات has مع خصائص type و key و value.
  • missing هي مصفوفة من كائنات missing مع خصائص type و key و value.

عندما ترجع دالة rewrites مصفوفة، يتم تطبيق إعادة التوجيه بعد التحقق من نظام الملفات (الصفحات وملفات /public) وقبل المسارات الديناميكية. عندما ترجع دالة rewrites كائنًا من المصفوفات بشكل محدد، يمكن تغيير هذا السلوك والتحكم فيه بدقة أكبر، اعتبارًا من v10.1 من Next.js:

next.config.js
module.exports = {
  async rewrites() {
    return {
      beforeFiles: [
        // يتم التحقق من عمليات إعادة التوجيه هذه بعد الرؤوس/إعادة التوجيه
        // وقبل جميع الملفات بما في ذلك ملفات _next/public التي
        // تسمح بتجاوز ملفات الصفحة
        {
          source: '/some-page',
          destination: '/somewhere-else',
          has: [{ type: 'query', key: 'overrideMe' }],
        },
      ],
      afterFiles: [
        // يتم التحقق من عمليات إعادة التوجيه هذه بعد التحقق من ملفات الصفحات/العامة
        // ولكن قبل المسارات الديناميكية
        {
          source: '/non-existent',
          destination: '/somewhere-else',
        },
      ],
      fallback: [
        // يتم التحقق من عمليات إعادة التوجيه هذه بعد التحقق من ملفات الصفحات/العامة
        // والمسارات الديناميكية
        {
          source: '/:path*',
          destination: `https://my-old-site.com/:path*`,
        },
      ],
    }
  },
}

معلومة جيدة: عمليات إعادة التوجيه في beforeFiles لا تتحقق من نظام الملفات/المسارات الديناميكية مباشرة بعد مطابقة مصدر، بل تستمر حتى يتم التحقق من جميع beforeFiles.

ترتيب التحقق من مسارات Next.js هو:

  1. يتم التحقق من الرؤوس (headers) وتطبيقها
  2. يتم التحقق من عمليات إعادة التوجيه (redirects) وتطبيقها
  3. يتم التحقق من عمليات إعادة التوجيه beforeFiles وتطبيقها
  4. يتم التحقق من الملفات الثابتة من الدليل العام (public directory)، وملفات _next/static، والصفحات غير الديناميكية وتقديمها
  5. يتم التحقق من عمليات إعادة التوجيه afterFiles وتطبيقها، إذا تمت مطابقة أحد هذه الإعادة للتوجيه، نتحقق من المسارات الديناميكية/الملفات الثابتة بعد كل مطابقة
  6. يتم التحقق من عمليات إعادة التوجيه fallback وتطبيقها، يتم تطبيق هذه قبل عرض صفحة 404 وبعد التحقق من المسارات الديناميكية/جميع الأصول الثابتة. إذا كنت تستخدم fallback: true/'blocking' في getStaticPaths، فلن يتم تشغيل عمليات إعادة التوجيه fallback المحددة في next.config.js.

معلمات إعادة التوجيه

عند استخدام المعلمات في إعادة التوجيه، سيتم تمرير المعلمات في الاستعلام افتراضيًا عندما لا يتم استخدام أي من المعلمات في destination.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-about/:path*',
        destination: '/about', // معلمة :path غير مستخدمة هنا لذا سيتم تمريرها تلقائيًا في الاستعلام
      },
    ]
  },
}

إذا تم استخدام معلمة في الوجهة، فلن يتم تمرير أي من المعلمات تلقائيًا في الاستعلام.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/docs/:path*',
        destination: '/:path*', // معلمة :path مستخدمة هنا لذا لن يتم تمريرها تلقائيًا في الاستعلام
      },
    ]
  },
}

لا يزال بإمكانك تمرير المعلمات يدويًا في الاستعلام إذا تم استخدام أحدها بالفعل في الوجهة عن طريق تحديد الاستعلام في destination.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/:first/:second',
        destination: '/:first?second=:second',
        // نظرًا لأن معلمة :first مستخدمة في الوجهة، لن تتم إضافة معلمة :second
        // تلقائيًا في الاستعلام على الرغم من أنه يمكننا إضافتها يدويًا
        // كما هو موضح أعلاه
      },
    ]
  },
}

معلومة جيدة: سيتم تحليل معلمات الصفحات الثابتة من التحسين الثابت التلقائي (Automatic Static Optimization) أو التقديم المسبق (prerendering) من عمليات إعادة التوجيه على العميل بعد الترطيب وتوفيرها في الاستعلام.

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

يُسمح بمطابقة المسار، على سبيل المثال /blog/:slug سيطابق /blog/hello-world (بدون مسارات متداخلة):

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug',
        destination: '/news/:slug', // يمكن استخدام المعلمات المطابقة في الوجهة
      },
    ]
  },
}

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

لمطابقة مسار بدل، يمكنك استخدام * بعد معلمة، على سبيل المثال /blog/:slug* سيطابق /blog/a/b/c/d/hello-world:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:slug*',
        destination: '/news/:slug*', // يمكن استخدام المعلمات المطابقة في الوجهة
      },
    ]
  },
}

مطابقة مسار التعبير العادي (Regex)

لمطابقة مسار تعبير عادي، يمكنك لف التعبير بين قوسين بعد معلمة، على سبيل المثال /blog/:slug(\\d{1,}) سيطابق /blog/123 ولكن ليس /blog/abc:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-blog/:post(\\d{1,})',
        destination: '/blog/:post', // يمكن استخدام المعلمات المطابقة في الوجهة
      },
    ]
  },
}

يتم استخدام الأحرف التالية (, ), {, }, [, ], |, \, ^, ., :, *, +, -, ?, $ لمطابقة مسار التعبير العادي، لذا عند استخدامها في source كقيم غير خاصة، يجب تهريبها عن طريق إضافة \\ قبلها:

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        // هذا سيطابق `/english(default)/something` عند الطلب
        source: '/english\\(default\\)/:slug',
        destination: '/en-us/:slug',
      },
    ]
  },
}

مطابقة الرأس، الكوكي، والاستعلام

لمطابقة إعادة التوجيه فقط عندما تتطابق قيم الرأس أو الكوكي أو الاستعلام مع حقل has أو لا تتطابق مع حقل missing، يمكن استخدام has أو missing. يجب أن يتطابق كل من source وجميع عناصر has وألا تتطابق جميع عناصر missing لتطبيق إعادة التوجيه.

يمكن أن تحتوي عناصر has و missing على الحقول التالية:

  • type: String - يجب أن يكون إما header أو cookie أو host أو query.
  • key: String - المفتاح من النوع المحدد للمطابقة ضده.
  • value: String أو undefined - القيمة للتحقق منها، إذا كانت undefined فستطابق أي قيمة. يمكن استخدام سلسلة تشبه التعبير العادي لالتقاط جزء محدد من القيمة، على سبيل المثال إذا تم استخدام القيمة first-(?<paramName>.*) لـ first-second، فيمكن استخدام second في الوجهة مع :paramName.
next.config.js
module.exports = {
  async rewrites() {
    return [
      // إذا كان رأس `x-rewrite-me` موجودًا،
      // سيتم تطبيق إعادة التوجيه هذه
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // إذا كان رأس `x-rewrite-me` غير موجود،
      // سيتم تطبيق إعادة التوجيه هذه
      {
        source: '/:path*',
        missing: [
          {
            type: 'header',
            key: 'x-rewrite-me',
          },
        ],
        destination: '/another-page',
      },
      // إذا تمت مطابقة المصدر والاستعلام والكوكي،
      // سيتم تطبيق إعادة التوجيه هذه
      {
        source: '/specific/:path*',
        has: [
          {
            type: 'query',
            key: 'page',
            // لن تكون قيمة الصفحة متاحة في
            // الوجهة نظرًا لتوفير القيمة وعدم
            // استخدام مجموعة التقاط مسماة مثل (?<page>home)
            value: 'home',
          },
          {
            type: 'cookie',
            key: 'authorized',
            value: 'true',
          },
        ],
        destination: '/:path*/home',
      },
      // إذا كان رأس `x-authorized` موجودًا و
      // يحتوي على قيمة مطابقة، سيتم تطبيق إعادة التوجيه هذه
      {
        source: '/:path*',
        has: [
          {
            type: 'header',
            key: 'x-authorized',
            value: '(?<authorized>yes|true)',
          },
        ],
        destination: '/home?authorized=:authorized',
      },
      // إذا كان المضيف هو `example.com`،
      // سيتم تطبيق إعادة التوجيه هذه
      {
        source: '/:path*',
        has: [
          {
            type: 'host',
            value: 'example.com',
          },
        ],
        destination: '/another-page',
      },
    ]
  },
}

إعادة التوجيه إلى عنوان URL خارجي

أمثلة

تسمح لك عمليات إعادة التوجيه بإعادة التوجيه إلى عنوان URL خارجي. هذا مفيد بشكل خاص للتبني التدريجي لـ Next.js. فيما يلي مثال لإعادة توجيه مسار /blog من تطبيقك الرئيسي إلى موقع خارجي.

next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog',
        destination: 'https://example.com/blog',
      },
      {
        source: '/blog/:slug',
        destination: 'https://example.com/blog/:slug', // يمكن استخدام المعلمات المطابقة في الوجهة
      },
    ]
  },
}

إذا كنت تستخدم trailingSlash: true، فأنت بحاجة أيضًا إلى إدراج شرطة مائلة في معلمة source. إذا كان خادم الوجهة يتوقع أيضًا شرطة مائلة، فيجب تضمينها في معلمة destination.

next.config.js
module.exports = {
  trailingSlash: true,
  async rewrites() {
    return [
      {
        source: '/blog/',
        destination: 'https://example.com/blog/',
      },
      {
        source: '/blog/:path*/',
        destination: 'https://example.com/blog/:path*/',
      },
    ]
  },
}

التبني التدريجي لـ Next.js

يمكنك أيضًا جعل Next.js يعود إلى الوكيل لموقع ويب موجود بعد التحقق من جميع مسارات Next.js.

بهذه الطريقة لا تحتاج إلى تغيير تكوين إعادة التوجيه عند نقل المزيد من الصفحات إلى Next.js

next.config.js
module.exports = {
  async rewrites() {
    return {
      fallback: [
        {
          source: '/:path*',
          destination: `https://custom-routes-proxying-endpoint.vercel.app/:path*`,
        },
      ],
    }
  },
}

إعادة التوجيه مع دعم basePath

عند الاستفادة من دعم basePath مع إعادة التوجيه، يتم إضافة basePath تلقائيًا إلى كل source و destination ما لم تقم بإضافة basePath: false إلى إعادة التوجيه:

next.config.js
module.exports = {
  basePath: '/docs',

  async rewrites() {
    return [
      {
        source: '/with-basePath', // يصبح تلقائيًا /docs/with-basePath
        destination: '/another', // يصبح تلقائيًا /docs/another
      },
      {
        // لا يضيف /docs إلى /without-basePath نظرًا لتعيين basePath: false
        // ملاحظة: لا يمكن استخدام هذا لإعادة التوجيه الداخلية مثل `destination: '/another'`
        source: '/without-basePath',
        destination: 'https://example.com',
        basePath: false,
      },
    ]
  },
}

سجل الإصدارات

الإصدارالتغييرات
v13.3.0تمت إضافة missing.
v10.2.0تمت إضافة has.
v9.5.0تمت إضافة الرؤوس.