ترويسات 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 يعمل أيضاً في الاتجاهين، بمعنى مختلف في كل منهما.

جرّبها: فاحص ترويسات الطلب جرّبها: محلّل ترويسات HTTP

خمس ترويسات في كل اختبار تقريباً

التبادل أدناه يحفظ اللغة المفضلة لعميل في متجر تجريبي. وكل ترويسة من الخمس تجيب عن سؤال مختلف.

عند حفظ تفضيل اللغة: يصف 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. 1Content-Typeيصف جسم كل رسالة: JSON في الطلب، وJSON مع charset في الاستجابة. ويجب أن يطابق البايتات؛ والصيغة التي لا يقبلها الخادم تُقابَل بـ415.الطلب والاستجابة
  2. 2Acceptما يقبله العميل في الرد. وإن لم يتطابق شيء: 406، أو الصيغة الافتراضية للخادم، بحسب العقد.الطلب
  3. 3Authorizationمخطط ثم بيانات اعتماد. وإن غابت أو كانت غير صالحة: 401 مع WWW-Authenticate. وأخفِ القيمة في كل تقرير.الطلب
  4. 4Cache-Controlno-store: لا يجوز لأي ذاكرة تخزين مؤقت الاحتفاظ بنسخة، وهي القاعدة الصحيحة للبيانات الشخصية. أما no-cache فيسمح بالتخزين مع إعادة التحقق.الاستجابة
  5. 5Set-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"}

جرّبها: مدقّق Content-Type جرّبها: منشئ ترويسات HTTP

ما الذي تختبره في الترويسات

الترويسات جزء من العقد، فمكانها في أساس الاختبار (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 فقط)، في مواقع تملكها أو لديك إذن مكتوب باختبارها فقط.

جرّبها: مدقّق ترويسات API جرّبها: محلّل ترويسات الأمان

مثال تطبيقي: استجابة الملف الشخصي

يفحص مختبِر نقطة نهاية (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"}
الخطوات
  1. صنّف الترويسات إلى طلب واستجابة.
  2. قارن كل Content-Type بجسمه وبالعقد؛ وافحص Accept.
  3. فُكّ ترميز بيانات الاعتماد؛ وافحص ترويسات التخزين المؤقت وملف تعريف الارتباط والمعلومات.
  4. اكتب ثلاثة اختبارات سلبية، لكل منها ترويسة طلب واحدة.
إظهار الإجابة النموذجية
الإجابة النموذجية

ترويسات الطلب: 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 SemanticsIETF · 2022معاني أساليب HTTP وحقول الترويسات ورموز الحالة والتفاوض على المحتوى، بغضّ النظر عن إصدار البروتوكول.
  • RFC 9111: HTTP CachingIETF · 2022كيف تحدد Cache-Control وExpires وETag والمتحقِّقات ما إذا كان يمكن تخزين الاستجابة وإعادة استخدامها.
  • OWASP Cheat Sheet Series: HTTP HeadersOWASP Foundationأي ترويسات أمنية تُرسَل (HSTS وCSP وX-Content-Type-Options وحماية الإطارات) وأيها تُزال (Server وX-Powered-By).
  • HTTP headers — MDNMDN Web Docs (Mozilla)مرجع لترويسات الطلب والاستجابة: الصياغة والتوجيهات ودعم المتصفحات.

تدرّب بأدوات متقن

تحليل ترويسات طلبات واستجابات HTTP الخام إلى جدول منظّم مع الشروحات.

الويب

افحص ترويسات الطلب التي يرسلها متصفحك أو عميلك، مع شرح لكل منها.

اختبار واجهات API

تحقّق من ترويسات استجابة API من حيث الصحة والأمان وأفضل ممارسات التخزين المؤقت.

اختبار واجهات API

التحقق من صحة ترويسات Content-Type والتأكد من أن متن الاستجابة يطابق فعلاً نوع الوسائط المعلن.

الويب

فكّ ترميز سلاسل Base64 أو Base64url إلى نص، مع إصلاح الحشو تلقائياً.

الترميز

للتعمّق أكثر

تقدّمك في هذا الموضوع

جزء من مسار تعلم ضمان الجودة