رؤوس (headers)
تسمح لك الرؤوس بتعيين رؤوس HTTP مخصصة على الاستجابة لطلب وارد على مسار معين.
لتعيين رؤوس HTTP مخصصة، يمكنك استخدام مفتاح headers
في ملف next.config.js
:
module.exports = {
async headers() {
return [
{
source: '/about',
headers: [
{
key: 'x-custom-header',
value: 'قيمة الرأس المخصصة',
},
{
key: 'x-another-custom-header',
value: 'قيمة رأس مخصص آخر',
},
],
},
]
},
}
headers
هي دالة غير متزامنة تتوقع إرجاع مصفوفة تحتوي على كائنات ذات خصائص source
و headers
:
source
: نمط مسار الطلب الوارد.headers
: مصفوفة من كائنات رأس الاستجابة، مع خصائصkey
وvalue
.basePath
:false
أوundefined
- إذا كانت false فلن يتم تضمين basePath عند المطابقة، يمكن استخدامها لإعادة الكتابة الخارجية فقط.locale
:false
أوundefined
- ما إذا كان يجب عدم تضمين اللغة عند المطابقة.has
: مصفوفة من كائنات has مع خصائصtype
وkey
وvalue
.missing
: مصفوفة من كائنات missing مع خصائصtype
وkey
وvalue
.
يتم التحقق من الرؤوس قبل نظام الملفات الذي يتضمن الصفحات وملفات /public
.
سلوك تجاوز الرؤوس
إذا تطابق رأسان على نفس المسار وقاما بتعيين نفس مفتاح الرأس، فإن مفتاح الرأس الأخير سيتجاوز الأول. باستخدام الرؤوس أدناه، سيؤدي المسار /hello
إلى أن يكون رأس x-hello
بقيمة world
بسبب تعيين آخر قيمة للرأس كـ world
.
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'x-hello',
value: 'there',
},
],
},
{
source: '/hello',
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
]
},
}
مطابقة المسار
يُسمح بمطابقة المسار، على سبيل المثال /blog/:slug
سيطابق /blog/hello-world
(بدون مسارات متداخلة):
module.exports = {
async headers() {
return [
{
source: '/blog/:slug',
headers: [
{
key: 'x-slug',
value: ':slug', // يمكن استخدام المعلمات المتطابقة في القيمة
},
{
key: 'x-slug-:slug', // يمكن استخدام المعلمات المتطابقة في المفتاح
value: 'قيمة رأس مخصص آخر',
},
],
},
]
},
}
مطابقة مسار Wildcard
لمطابقة مسار wildcard، يمكنك استخدام *
بعد معلمة، على سبيل المثال /blog/:slug*
سيطابق /blog/a/b/c/d/hello-world
:
module.exports = {
async headers() {
return [
{
source: '/blog/:slug*',
headers: [
{
key: 'x-slug',
value: ':slug*', // يمكن استخدام المعلمات المتطابقة في القيمة
},
{
key: 'x-slug-:slug*', // يمكن استخدام المعلمات المتطابقة في المفتاح
value: 'قيمة رأس مخصص آخر',
},
],
},
]
},
}
مطابقة مسار Regex
لمطابقة مسار regex، يمكنك لف الـ regex بين قوسين بعد معلمة، على سبيل المثال /blog/:slug(\\d{1,})
سيطابق /blog/123
ولكن ليس /blog/abc
:
module.exports = {
async headers() {
return [
{
source: '/blog/:post(\\d{1,})',
headers: [
{
key: 'x-post',
value: ':post',
},
],
},
]
},
}
الأحرف التالية (
, )
, {
, }
, :
, *
, +
, ?
تُستخدم لمطابقة مسار regex، لذلك عند استخدامها في source
كقيم غير خاصة يجب الهروب منها بإضافة \\
قبلها:
module.exports = {
async headers() {
return [
{
// هذا سيطابق طلب `/english(default)/something`
source: '/english\\(default\\)/:slug',
headers: [
{
key: 'x-header',
value: 'value',
},
],
},
]
},
}
مطابقة الرأس، الكوكي، والاستعلام
لتطبيق رأس فقط عندما تتطابق قيم الرأس أو الكوكي أو الاستعلام مع حقل has
أو لا تتطابق مع حقل missing
، يمكن استخدام has
أو missing
. يجب أن يتطابق كل من source
وجميع عناصر has
وألا تتطابق جميع عناصر missing
لتطبيق الرأس.
يمكن أن تحتوي عناصر has
و missing
على الحقول التالية:
type
:String
- يجب أن يكون إماheader
أوcookie
أوhost
أوquery
.key
:String
- المفتاح من النوع المحدد للمطابقة ضده.value
:String
أوundefined
- القيمة للتحقق منها، إذا كانت undefined فستتطابق أي قيمة. يمكن استخدام سلسلة تشبه regex لالتقاط جزء معين من القيمة، على سبيل المثال إذا تم استخدام القيمةfirst-(?<paramName>.*)
لـfirst-second
فإنsecond
سيكون قابلاً للاستخدام في الوجهة مع:paramName
.
module.exports = {
async headers() {
return [
// إذا كان رأس `x-add-header` موجودًا،
// سيتم تطبيق رأس `x-another-header`
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-add-header',
},
],
headers: [
{
key: 'x-another-header',
value: 'hello',
},
],
},
// إذا كان رأس `x-no-header` غير موجود،
// سيتم تطبيق رأس `x-another-header`
{
source: '/:path*',
missing: [
{
type: 'header',
key: 'x-no-header',
},
],
headers: [
{
key: 'x-another-header',
value: 'hello',
},
],
},
// إذا تمت مطابقة المصدر والاستعلام والكوكي،
// سيتم تطبيق رأس `x-authorized`
{
source: '/specific/:path*',
has: [
{
type: 'query',
key: 'page',
// لن تكون قيمة الصفحة متاحة في
// مفاتيح/قيم الرأس حيث يتم توفير القيمة و
// لا تستخدم مجموعة capture مسماة مثل (?<page>home)
value: 'home',
},
{
type: 'cookie',
key: 'authorized',
value: 'true',
},
],
headers: [
{
key: 'x-authorized',
value: ':authorized',
},
],
},
// إذا كان رأس `x-authorized` موجودًا و
// يحتوي على قيمة مطابقة، سيتم تطبيق `x-another-header`
{
source: '/:path*',
has: [
{
type: 'header',
key: 'x-authorized',
value: '(?<authorized>yes|true)',
},
],
headers: [
{
key: 'x-another-header',
value: ':authorized',
},
],
},
// إذا كان المضيف هو `example.com`،
// سيتم تطبيق هذا الرأس
{
source: '/:path*',
has: [
{
type: 'host',
value: 'example.com',
},
],
headers: [
{
key: 'x-another-header',
value: ':authorized',
},
],
},
]
},
}
الرؤوس مع دعم basePath
عند الاستفادة من دعم basePath مع الرؤوس، يتم تلقائيًا إضافة بادئة basePath
إلى كل source
ما لم تقم بإضافة basePath: false
إلى الرأس:
module.exports = {
basePath: '/docs',
async headers() {
return [
{
source: '/with-basePath', // تصبح /docs/with-basePath
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
{
source: '/without-basePath', // لا يتم تعديلها حيث تم تعيين basePath: false
headers: [
{
key: 'x-hello',
value: 'world',
},
],
basePath: false,
},
]
},
}
الرؤوس مع دعم i18n
عند الاستفادة من دعم i18n مع الرؤوس، يتم تلقائيًا إضافة بادئة إلى كل source
للتعامل مع locales
المكونة ما لم تقم بإضافة locale: false
إلى الرأس. إذا تم استخدام locale: false
، يجب إضافة بادئة إلى source
بلغة لتتم مطابقتها بشكل صحيح.
module.exports = {
i18n: {
locales: ['en', 'fr', 'de'],
defaultLocale: 'en',
},
async headers() {
return [
{
source: '/with-locale', // يتعامل تلقائيًا مع جميع اللغات
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
{
// لا يتعامل مع اللغات تلقائيًا حيث تم تعيين locale: false
source: '/nl/with-locale-manual',
locale: false,
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
{
// هذا يطابق '/' حيث أن `en` هي defaultLocale
source: '/en',
locale: false,
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
{
// هذا يتحول إلى /(en|fr|de)/(.*) لذا لن يطابق
// المسارات الأساسية `/` أو `/fr` مثل /:path*
source: '/(.*)',
headers: [
{
key: 'x-hello',
value: 'world',
},
],
},
]
},
}
Cache-Control
يضبط Next.js رأس Cache-Control
بقيمة public, max-age=31536000, immutable
للأصول غير القابلة للتغيير حقًا. لا يمكن تجاوز هذا. تحتوي هذه الملفات غير القابلة للتغيير على SHA-hash في اسم الملف، لذا يمكن تخزينها مؤقتًا بشكل آمن إلى أجل غير مسمى. على سبيل المثال، استيراد الصور الثابتة. لا يمكنك تعيين رؤوس Cache-Control
في next.config.js
لهذه الأصول.
ومع ذلك، يمكنك تعيين رؤوس Cache-Control
للاستجابات أو البيانات الأخرى.
إذا كنت بحاجة إلى إعادة التحقق من ذاكرة التخزين المؤقت لصفحة تم توليدها بشكل ثابت، يمكنك القيام بذلك عن طريق تعيين خاصية revalidate
في دالة getStaticProps
للصفحة.
لتخزين الاستجابة من مسار API، يمكنك استخدام res.setHeader
:
import type { NextApiRequest, NextApiResponse } from 'next'
type ResponseData = {
message: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
res.setHeader('Cache-Control', 's-maxage=86400')
res.status(200).json({ message: 'Hello from Next.js!' })
}
export default function handler(req, res) {
res.setHeader('Cache-Control', 's-maxage=86400')
res.status(200).json({ message: 'Hello from Next.js!' })
}
يمكنك أيضًا استخدام رؤوس التخزين المؤقت (Cache-Control
) داخل getServerSideProps
لتخزين الاستجابات الديناميكية مؤقتًا. على سبيل المثال، باستخدام stale-while-revalidate
.
import { GetStaticProps, GetStaticPaths, GetServerSideProps } from 'next'
// تعتبر هذه القيمة جديدة لمدة عشر ثوانٍ (s-maxage=10).
// إذا تم تكرار الطلب خلال الثواني العشر التالية، ستظل القيمة المخزنة مؤقتًا جديدة. إذا تم تكرار الطلب قبل 59 ثانية،
// ستكون القيمة المخزنة مؤقتًا قديمة ولكنها ستظل تُعرض (stale-while-revalidate=59).
//
// في الخلفية، سيتم عمل طلب إعادة تحقق لملء ذاكرة التخزين المؤقت
// بقيمة جديدة. إذا قمت بتحديث الصفحة، سترى القيمة الجديدة.
export const getServerSideProps = (async (context) => {
context.res.setHeader(
'Cache-Control',
'public, s-maxage=10, stale-while-revalidate=59'
)
return {
props: {},
}
}) satisfies GetServerSideProps
// تعتبر هذه القيمة جديدة لمدة عشر ثوانٍ (s-maxage=10).
// إذا تم تكرار الطلب خلال الثواني العشر التالية، ستظل القيمة المخزنة مؤقتًا جديدة. إذا تم تكرار الطلب قبل 59 ثانية،
// ستكون القيمة المخزنة مؤقتًا قديمة ولكنها ستظل تُعرض (stale-while-revalidate=59).
//
// في الخلفية، سيتم عمل طلب إعادة تحقق لملء ذاكرة التخزين المؤقت
// بقيمة جديدة. إذا قمت بتحديث الصفحة، سترى القيمة الجديدة.
export async function getServerSideProps({ req, res }) {
res.setHeader(
'Cache-Control',
'public, s-maxage=10, stale-while-revalidate=59'
)
return {
props: {},
}
}
الخيارات
CORS
مشاركة الموارد عبر المصادر (CORS) هي ميزة أمان تتيح لك التحكم في المواقع التي يمكنها الوصول إلى مواردك. يمكنك تعيين رأس Access-Control-Allow-Origin
للسماح لمصدر معين بالوصول إلى نقاط نهاية API الخاصة بك.
async headers() {
return [
{
source: "/api/:path*",
headers: [
{
key: "Access-Control-Allow-Origin",
value: "*", // حدد المصدر الخاص بك
},
{
key: "Access-Control-Allow-Methods",
value: "GET, POST, PUT, DELETE, OPTIONS",
},
{
key: "Access-Control-Allow-Headers",
value: "Content-Type, Authorization",
},
],
},
];
},
X-DNS-Prefetch-Control
هذا الرأس يتحكم في prefetching لـ DNS، مما يسمح للمتصفحات بإجراء تحليل اسم النطاق بشكل استباقي على الروابط الخارجية والصور وCSS وJavaScript والمزيد. يتم تنفيذ هذا prefetching في الخلفية، لذا يكون DNS أكثر احتمالية لحلها بحلول الوقت الذي تكون فيه العناصر المشار إليها مطلوبة. هذا يقلل من زمن الوصول عندما ينقر المستخدم على رابط.
{
key: 'X-DNS-Prefetch-Control',
value: 'on'
}
Strict-Transport-Security
هذا الرأس يخبر المتصفحات أنه يجب الوصول إليه فقط باستخدام HTTPS، بدلاً من استخدام HTTP. باستخدام التكوين أدناه، ستستخدم جميع النطاقات الفرعية الحالية والمستقبلية HTTPS لمدة max-age
تبلغ عامين. هذا يمنع الوصول إلى الصفحات أو النطاقات الفرعية التي يمكن تقديمها فقط عبر HTTP.
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload'
}
X-Frame-Options
هذا الرأس يشير إلى ما إذا كان يجب السماح بعرض الموقع داخل iframe
. يمكن أن يمنع هذا من هجمات clickjacking.
تم استبدال هذا الرأس بخيار frame-ancestors
في CSP، والذي يتمتع بدعم أفضل في المتصفحات الحديثة (انظر سياسة أمان المحتوى للحصول على تفاصيل التكوين).
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN'
}
سياسة الأذونات (Permissions-Policy)
هذا الرأس يسمح لك بالتحكم في الميزات وواجهات برمجة التطبيقات (APIs) التي يمكن استخدامها في المتصفح. كان يُعرف سابقًا باسم Feature-Policy
.
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=(), browsing-topics=()'
}
خيارات نوع المحتوى (X-Content-Type-Options)
هذا الرأس يمنع المتصفح من محاولة تخمين نوع المحتوى إذا لم يتم تعيين رأس Content-Type
بشكل صريح. يمكن أن يمنع هذا استغلال ثغرات XSS للمواقع التي تسمح للمستخدمين بتحميل ومشاركة الملفات.
على سبيل المثال، عندما يحاول مستخدم تنزيل صورة، ولكن يتم معاملتها كنوع مختلف من Content-Type
مثل ملف تنفيذي، والذي قد يكون ضارًا. ينطبق هذا الرأس أيضًا على تنزيل ملحقات المتصفح. القيمة الوحيدة الصالحة لهذا الرأس هي nosniff
.
{
key: 'X-Content-Type-Options',
value: 'nosniff'
}
سياسة المُحيل (Referrer-Policy)
هذا الرأس يتحكم في مقدار المعلومات التي يدرجها المتصفح عند الانتقال من الموقع الحالي (الأصل) إلى موقع آخر.
{
key: 'Referrer-Policy',
value: 'origin-when-cross-origin'
}
سياسة أمان المحتوى (Content-Security-Policy)
تعرف على المزيد حول إضافة سياسة أمان المحتوى إلى تطبيقك.
سجل الإصدارات
الإصدار | التغييرات |
---|---|
v13.3.0 | تمت إضافة missing . |
v10.2.0 | تمت إضافة has . |
v9.5.0 | تمت إضافة الرؤوس. |