ترويسات HTTP
ترويسات HTTP (HTTP Headers) حقول مسمّاة ترافق كل طلب وكل استجابة، وتصف الرسالة بدلاً من أن تحمل بياناتها. وكما في درس الطلبات والاستجابات، تقع بين سطر البداية والجسم في أسطر بالصيغة Name: value، ويسمّيها RFC 9110 حقول الترويسة (Header Fields). وهي تقول بأي صيغة الجسم، ومن يطلب، وكم من الوقت يجوز تخزين الرد مؤقتاً، وما الذي ينبغي تذكّره.
مثلاً، عندما يحفظ تطبيق متجر اللغة المفضلة لعميل، يحمل الطلب Content-Type: application/json (هذا الجسم بصيغة JSON)، وAccept: application/json (أجبني بـJSON)، وAuthorization: Bearer … (هذه هويتي). وتضيف الاستجابة Cache-Control: no-store (لا تحتفظ بنسخة) وSet-Cookie: lang=ar (تذكّر هذا). لا يظهر شيء من ذلك على الشاشة، ومع ذلك يحدد كل سطر ما إذا كانت الميزة تعمل وما إذا كانت آمنة.
لماذا يهم
كثير من العيوب لا يظهر إلا في الترويسات. فجسم JSON صحيح يحمل الوسم Content-Type: text/html يُعطّل العملاء الذين يثقون بالوسم. والملف الشخصي المُرسَل مع Cache-Control: public قد تخزّنه ذاكرة تخزين مؤقت مشتركة (Shared Cache)، مثل شبكة توصيل المحتوى (CDN)، وتقدّمه للمستخدم التالي. وملف تعريف ارتباط الجلسة (Session Cookie) الذي يُضبط دون Secure قد ينتقل عبر HTTP غير المشفّر. وفي كل مرة تبدو الشاشة سليمة وينجح اختبار الواجهة.
والترويسات تفسّر الإخفاق بسرعة أيضاً: Content-Type لماذا تعذّر تحليل الجسم، وWWW-Authenticate أيّ مصادقة كان يتوقعها الاستدعاء المرفوض، وCache-Control وAge (عمر النسخة المخزّنة بالثواني) لماذا ما زالت صفحة أُصلحت تبدو قديمة.
كيف تُكتب الترويسات وكيف تُقرأ
أسماء الحقول لا تتأثر بحالة الأحرف: Content-Type وcontent-type ترويسة واحدة، ويرسل HTTP/2 وHTTP/3 كل الأسماء بأحرف صغيرة، ولهذا تعرض أدوات المطوّر (DevTools) كثيراً content-type. أما حساسية القيمة لحالة الأحرف فتعتمد على الترويسة: أنواع الوسائط (Media Types) مثل application/json لا تتأثر، ورموز الوصول (Access Tokens) وقيم ملفات تعريف الارتباط تتأثر.
وقد تتكرر الترويسة أكثر من مرة. ففي الترويسات التي قيمتها قائمة، مثل Accept، يجوز للمستلم أن يجمع الأسطر في سطر واحد مفصول بفواصل؛ ويسمّي RFC 9110 الترويسة Set-Cookie استثناءً: ملف تعريف ارتباط واحد في كل سطر، ولا دمج أبداً. وتنقسم الترويسات إلى مجموعات:
- ترويسات الطلب تصف العميل وما يريده:
Host(إلزامية في HTTP/1.1)، وUser-Agent، وAccept، وAccept-Language، وAuthorization، وCookie. - ترويسات الاستجابة تصف الرد:
Set-Cookie، وLocation، وWWW-Authenticate، وRetry-After، وServer. - ترويسات المحتوى تصف الجسم في أي اتجاه:
Content-Type، وContent-Length، وContent-Encoding. وCache-Controlيعمل أيضاً في الاتجاهين، بمعنى مختلف في كل منهما.
خمس ترويسات في كل اختبار تقريباً
التبادل أدناه يحفظ اللغة المفضلة لعميل في متجر تجريبي. وكل ترويسة من الخمس تجيب عن سؤال مختلف.
Content-Type الجسم في الاتجاهين، ويرافق Accept وAuthorization الطلب، وتردّ الاستجابة بـCache-Control: no-store وبترويسة Set-Cookie.الطلب
PUT /api/v1/me/preferences HTTP/1.1 Host: test.shop.example.com الجزء 1:Content-Type: application/json الجزء 2:Accept: application/json الجزء 3:Authorization: Bearer eyJhbGciOi... Content-Length: 18 {"language": "ar"}
الاستجابة
HTTP/1.1 200 OK الجزء 1:Content-Type: application/json; charset=utf-8 Content-Length: 55 الجزء 4:Cache-Control: no-store الجزء 5:Set-Cookie: lang=ar; Path=/; Max-Age=31536000; Secure {"language": "ar", "updatedAt": "2026-10-01T09:30:00Z"}
- 1
Content-Typeيصف جسم كل رسالة: JSON في الطلب، وJSON معcharsetفي الاستجابة. ويجب أن يطابق البايتات؛ والصيغة التي لا يقبلها الخادم تُقابَل بـ415.الطلب والاستجابة - 2
Acceptما يقبله العميل في الرد. وإن لم يتطابق شيء:406، أو الصيغة الافتراضية للخادم، بحسب العقد.الطلب - 3
Authorizationمخطط ثم بيانات اعتماد. وإن غابت أو كانت غير صالحة:401معWWW-Authenticate. وأخفِ القيمة في كل تقرير.الطلب - 4
Cache-Controlno-store: لا يجوز لأي ذاكرة تخزين مؤقت الاحتفاظ بنسخة، وهي القاعدة الصحيحة للبيانات الشخصية. أماno-cacheفيسمح بالتخزين مع إعادة التحقق.الاستجابة - 5
Set-Cookieيخزّنlang=arمدة سنة، ويعيده المتصفح فيCookie. وSecureيمنع إرساله عبر HTTP غير المشفّر.الاستجابة
Content-Type: نوع وسائط الجسم في هذه الرسالة، مع معاملات اختيارية مثلcharset. وبه يحلّل المستلم الجسم، لذا يجب أن يطابق البايتات الفعلية؛ والخادم الذي لا يقبل الصيغة ينبغي أن يردّ بـ415 Unsupported Media Type.Accept: أنواع الوسائط التي يقبلها العميل، ويمكن ترجيحها بأوزان (q=0.8). وإن لم يتوفر أيٌّ منها، يسمح RFC 9110 للخادم بالرد بـ406 Not Acceptableأو بتجاهل الترويسة وإرسال صيغته الافتراضية؛ وينبغي أن يحدد العقد أيّهما.Authorization: مخطط (Scheme) ثم بيانات اعتماد (Credentials)، مثلBearer <token>(رمز يُصدر عند تسجيل الدخول) أوBasic <credentials>(اسم المستخدم وكلمة المرور تفصل بينهما نقطتان). وبيانات الاعتماد المفقودة أو غير الصالحة تُقابَل بـ401 Unauthorized، ويوجب RFC 9110 أن تحمل هذه الاستجابة ترويسةWWW-Authenticate. وبيانات Basic مرمّزة بـBase64 وليست مشفّرة: يقرؤها كل من يراها.Cache-Control: توجيهات (Directives) لذاكرات التخزين المؤقت وفق RFC 9111.max-age=600: تبقى حديثة (Fresh) مدة 600 ثانية، فيجوز لذاكرة التخزين المؤقت إعادة استخدامها دون سؤال الخادم.no-cache: يجوز تخزينها، لكن يجب إعادة التحقق منها قبل كل استخدام.no-store: يُمنع تخزينها.private: لا يخزّنها إلا ذاكرة خاصة مثل المتصفح. ودرس التخزين المؤقت في HTTP يتعمّق في ذلك.Set-Cookie: تطلب من المتصفح تخزين ملف تعريف ارتباط (Cookie)، فيعيده في ترويسةCookieمع الطلبات المطابقة اللاحقة. وسمات مثلMax-AgeوSecureوHttpOnlyتتحكم في مدة بقائه ووجهته ومن يستطيع قراءته؛ ودرس ملفات تعريف الارتباط والجلسات يختبرها.
النسخة النصية
PUT /api/v1/me/preferences HTTP/1.1
Host: test.shop.example.com
Content-Type: application/json
Accept: application/json
Authorization: Bearer eyJhbGciOi...
Content-Length: 18
{"language": "ar"}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 55
Cache-Control: no-store
Set-Cookie: lang=ar; Path=/; Max-Age=31536000; Secure
{"language": "ar", "updatedAt": "2026-10-01T09:30:00Z"}ما الذي تختبره في الترويسات
الترويسات جزء من العقد، فمكانها في أساس الاختبار (Test Basis) وفي النتائج المتوقعة.
- فحوص الاستجابة:
Content-Typeالموثّق، مع جسم بهذه الصيغة فعلاً؛ وLocationبعد201 Createdإذا وعد العقد به؛ وCache-Control: no-storeعلى البيانات الشخصية وبيانات الاعتماد؛ والسمات المتفق عليها في كلSet-Cookie. - اختبارات الطلب، بتغيير واحد في كل مرة: دون
Authorizationأو برمز منتهي الصلاحية (401معWWW-Authenticate)؛ وجسم JSON مُرسَل بـContent-Type: text/plain(415، أو400الموثّق)؛ وصيغة فيAcceptلا تقدمها الواجهة البرمجية (406، أو الصيغة الافتراضية الموثّقة). وقد تُقابَل ترويسة مكررة أو قيمة ضخمة بـ400أو431 Request Header Fields Too Large؛ أما500أو الانهيار فعيب. - التسريب وترويسات الأمان:
Server: Apache/2.4.41 (Ubuntu)أوX-Powered-By: PHP/7.4.3تخبر المهاجمين بالإصدارات التي يبحثون عن ثغراتها؛ وتوصي ورقة OWASP المرجعية لترويسات HTTP (OWASP HTTP Headers Cheat Sheet) بحذفX-Powered-By، وبحذفServerأو إعطائها قيمة لا تكشف شيئاً. وافحص ترويسات الأمان المتفق عليها، مثلStrict-Transport-Security(التي تُلزم المتصفحات بالوصول إلى الموقع عبر HTTPS فقط)، في مواقع تملكها أو لديك إذن مكتوب باختبارها فقط.
مثال تطبيقي: استجابة الملف الشخصي
يفحص مختبِر نقطة نهاية (Endpoint) الملف الشخصي في تطبيق ويب لمتجر على بيئة الاختبار. رمز الحالة 200 والجسم صحيح، فينجح اختبار الواجهة، لكن التبادل الخام يحوي أربعة عيوب في الترويسات، لكل منها تقرير مستقل لأن كلاً منها قد يُصلح في مكان مختلف: شيفرة التطبيق، أو إعدادات الجلسة، أو إعدادات خادم الويب.
Content-Type: text/htmlعلى JSON: قد يعجز العملاء الذين يتبعون الترويسة عن تحليله بوصفه JSON، ويعرضه المتصفح بوصفه HTML، وهذا خطر حقن سكربت (Script Injection) متى احتوى حقل مُدخلاً من المستخدم. المتوقع:application/json.Cache-Control: public, max-age=3600على بيانات شخصية: قد تحتفظ ذاكرة مشتركة مثل CDN أو وكيل (Proxy) في شركة بالملف الشخصي ساعة كاملة وتقدّمه لشخص آخر. المتوقع:no-store.Set-Cookieيضبط ملف تعريف ارتباط الجلسة من جديد دونSecureوHttpOnly: قد ينتقل عبر HTTP غير مشفّر، وتستطيع سكربتات الصفحة قراءته. المتوقع: سمات ملف تعريف ارتباط الجلسة المتفق عليها.ServerوX-Powered-Byيكشفان الإصدارات الدقيقة. المتوقع: حذفهما أو جعلهما عامّين.- بعد الإصلاح يعيد اختبار التأكيد (Confirmation Testing) الطلب ويقارن الترويسات، وتنضم الفحوص الأربعة إلى مجموعة اختبارات الانحدار (Regression) للواجهة البرمجية.
GET /api/v1/me HTTP/1.1
Host: test.shop.example.com
Accept: application/json
Cookie: sid=9f2c41d7e0
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 62
Cache-Control: public, max-age=3600
Set-Cookie: sid=9f2c41d7e0; Path=/
Server: Apache/2.4.41 (Ubuntu)
X-Powered-By: PHP/7.4.3
{"id": 58, "name": "Test User", "email": "user58@example.com"}جرّبها: محلّل ترويسات HTTP جرّبها: محلّل ترويسات التخزين المؤقت جرّبها: محلّل ملفات تعريف الارتباط (Cookies)
أخطاء شائعة
- فحص رمز الحالة والجسم دون النظر إلى ترويسات الاستجابة أبداً.
- مقارنة أسماء الترويسات مع مراعاة حالة الأحرف في الاختبارات المؤتمتة، فتنكسر المجموعة عند الانتقال إلى HTTP/2 دون أي عيب.
- فهم
no-cacheعلى أنه «لا تخزين»: فهو يسمح بالتخزين مع إعادة التحقق. والتوجيه الذي يمنع التخزين هوno-store. - افتراض أن الطلب لا يحمل إلا الترويسات التي كتبتها: المتصفحات وعملاء API يضيفون
User-AgentوCookieوغيرها. - لصق قيم
AuthorizationأوCookieحقيقية في التقارير أو لقطات الشاشة: فمن ينسخها يتصرف باسم ذلك المستخدم. أخفِها.
من منظور ضمان الجودة
تظهر الترويسات في المراجعة وفي الاختبار وبعد الإصلاح. في مراجعة العقد: اسأل عن الترويسات التي تحتاجها كل نقطة نهاية وتعيدها، وعن الرد على قيمة Accept أو Content-Type غير مدعومة، وعن المدة التي يجوز فيها تخزين كل استجابة؛ والعقد الذي يسكت عن ذلك هو أول ملاحظاتك. وأثناء الاختبار احتفظ بالطلب والاستجابة الخامين مع كل نتيجة اختبار API.
وحوّل كل عيب ترويسة يُصلح إلى فحص انحدار. واسأل فريق DevOps عمّا يضيفه خادم الويب أو البوابة (Gateway) أو CDN أو يحذفه، لأن الترويسة قد تكون صحيحة في الشيفرة ثم تتغيّر في الطريق. وأخفِ بيانات الاعتماد في كل الأدلة.
تمرين عملي
راجع ترويسات تغيير عنوان التوصيل
يغيّر تطبيق الجوال لمتجر تجريبي عنوان توصيل طلب شراء. ويقول العقد: أجسام JSON فقط؛ وقيمة Content-Type غير المدعومة تُقابَل بـ415، وقيمة Accept غير المدعومة بـ406؛ والمصادقة بمخطط Basic عبر HTTPS؛ والاستجابات التي فيها بيانات شخصية تحمل Cache-Control: no-store.
راجع الترويسات أدناه وحدها، فجسم الاستجابة صحيح. اكتب كل مشكلة مع القيمة المتوقعة والخطر، ثم اكتب ثلاثة اختبارات سلبية يغيّر كل منها ترويسة طلب واحدة. وتفك أداة Base64 Decoder في متقن ترميز قيمة Authorization.
PATCH /api/v1/orders/88121/address HTTP/1.1
Host: test.shop.example.com
Content-Type: text/plain
Accept: application/xml
Authorization: Basic dGVzdGVyMTpUZXN0LVBhc3MtMTIz
Content-Length: 41
{"city": "Jeddah", "postalCode": "23436"}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 59
Cache-Control: no-cache
Set-Cookie: lastCity=Jeddah; Path=/; Max-Age=31536000
Server: nginx/1.18.0
{"orderId": 88121, "city": "Jeddah", "postalCode": "23436"}- صنّف الترويسات إلى طلب واستجابة.
- قارن كل
Content-Typeبجسمه وبالعقد؛ وافحصAccept. - فُكّ ترميز بيانات الاعتماد؛ وافحص ترويسات التخزين المؤقت وملف تعريف الارتباط والمعلومات.
- اكتب ثلاثة اختبارات سلبية، لكل منها ترويسة طلب واحدة.
إظهار الإجابة النموذجية
ترويسات الطلب: Host، وContent-Type، وAccept، وAuthorization، وContent-Length. وترويسات الاستجابة: Content-Type، وContent-Length، وCache-Control، وSet-Cookie، وServer. والصحيح منها: Host، وقيمتا Content-Length (41 و59 بايت)، وContent-Type في الاستجابة.
Content-Type: text/plain على JSON: التطبيق يرسل وسماً خاطئاً (المتوقع application/json)، والخادم قبِله بدلاً من الرد بـ415. الخطر: يتعطل التطبيق حالما يطبّق الخادم العقد. إنهما عيبان، فلكل منهما تقرير.
Accept: application/xml تلقّى JSON برمز 200. يسمح RFC 9110 بالسلوكين، لكن هذا العقد اختار 406، فالرد بـ200 عيب. الخطر: العميل الذي طلب XML لا يستطيع قراءة الرد. واسأل أيضاً لماذا يطلب التطبيق XML أصلاً.
قيمة Basic تُفك إلى tester1:Test-Pass-123، فـBase64 ليس تشفيراً. الخطر: كل من يرى الطلب يستطيع تسجيل الدخول باسم tester1. أرسلها عبر HTTPS فقط، وأخفِها في كل الأدلة، وغيّر كلمة المرور التي ظهرت في تقرير مشترك.
Cache-Control: no-cache يخالف قاعدة no-store: فما زال يجوز لذاكرة التخزين المؤقت الاحتفاظ بالعنوان إذا أعادت التحقق منه قبل إعادة استخدامه. المتوقع: no-store.
Set-Cookie: lastCity=Jeddah يحتفظ بجزء من العنوان مدة سنة دون Secure، فقد ينتقل عبر HTTP غير مشفّر: اسأل هل يلزم أصلاً، وإن لزم فأضف Secure. وServer: nginx/1.18.0 يكشف الإصدار الذي سيبحث المهاجمون عن ثغراته. المتوقع: حذفها أو جعل قيمتها عامة.
الاختبارات السلبية، ويبدأ كل منها من طلب صالح (application/json في Content-Type وAccept، وبيانات اعتماد صالحة) ويغيّر ترويسة واحدة: (1) دون Authorization ← 401 مع WWW-Authenticate لمخطط Basic، والعنوان دون تغيير؛ (2) جسم JSON نفسه مع Content-Type: application/xml ← 415، والعنوان دون تغيير؛ (3) Accept: image/png ← 406، وليس 500 أبداً.
أسئلة شائعة
هل أسماء الترويسات حساسة لحالة الأحرف؟
لا. يعرّف RFC 9110 أسماء الحقول بأنها غير حساسة لحالة الأحرف، ويرسلها HTTP/2 وHTTP/3 بأحرف صغيرة. أما القيم فمسألة أخرى: بعضها لا يتأثر بحالة الأحرف، مثل أنواع الوسائط والمعامل charset (UTF-8 تساوي utf-8)، وبعضها يتأثر، مثل رموز الوصول وقيم ملفات تعريف الارتباط، والقيم المخصصة ما لم ينص توثيقها على غير ذلك.
ما الفرق بين Accept وContent-Type؟
Content-Type يصف الجسم الموجود في هذه الرسالة، وAccept يصف ما يريده العميل في الاستجابة. والطلب الذي يرسل JSON ويريد JSON في المقابل يحمل الاثنتين: Content-Type: application/json وAccept: application/json. أما طلب GET فلا جسم له عادةً، فقد يحمل Accept ولا داعي لأن يحمل Content-Type.
أين أرى ترويسات الطلب؟
في المتصفح: افتح أدوات المطوّر (DevTools)، واختر الطلب في لوحة الشبكة (Network)، ثم افتح تبويب Headers الذي يعرض ترويسات الطلب وترويسات الاستجابة منفصلة. ويعرضها عميل API في تبويب خاص بالاستجابة، والأمر curl -i يطبع ترويسات الاستجابة، وcurl -v يطبع الاتجاهين. وأداة Request Header Inspector في متقن تعرض ما يرسله متصفحك فعلاً.
المراجع
- RFC 9110: HTTP Semanticsمعاني أساليب HTTP وحقول الترويسات ورموز الحالة والتفاوض على المحتوى، بغضّ النظر عن إصدار البروتوكول.
- RFC 9111: HTTP Cachingكيف تحدد Cache-Control وExpires وETag والمتحقِّقات ما إذا كان يمكن تخزين الاستجابة وإعادة استخدامها.
- OWASP Cheat Sheet Series: HTTP Headersأي ترويسات أمنية تُرسَل (HSTS وCSP وX-Content-Type-Options وحماية الإطارات) وأيها تُزال (Server وX-Powered-By).
- HTTP headers — MDNمرجع لترويسات الطلب والاستجابة: الصياغة والتوجيهات ودعم المتصفحات.
تدرّب بأدوات متقن
تحليل ترويسات طلبات واستجابات HTTP الخام إلى جدول منظّم مع الشروحات.
افحص ترويسات الطلب التي يرسلها متصفحك أو عميلك، مع شرح لكل منها.
تحقّق من ترويسات استجابة API من حيث الصحة والأمان وأفضل ممارسات التخزين المؤقت.
التحقق من صحة ترويسات Content-Type والتأكد من أن متن الاستجابة يطابق فعلاً نوع الوسائط المعلن.
تحليل ترويسات Cache-Control وExpires وETag وLast-Modified وVary وAge، وشرح كيفية تخزين المتصفحات وشبكات CDN للاستجابة مؤقتاً.
فكّ ترميز سلاسل Base64 أو Base64url إلى نص، مع إصلاح الحشو تلقائياً.
للتعمّق أكثر
تقدّمك في هذا الموضوع
سجّل الدخول لتتابع تقدّمك
علّم الموضوعات مكتملة، وتابع من حيث توقفت، وافتح امتحانات التخصص.