طلبات HTTP واستجاباتها
كل تبادل على الويب زوج من الرسائل: يرسل العميل طلب HTTP (Request)، ويعيد الخادم استجابة HTTP (Response). يقول الطلب ما يريده العميل: طريقة (Method) مثل POST، وهدفاً مثل /api/v1/tickets، وترويسات (Headers)، وجسماً (Body) عندما توجد بيانات للإرسال. وتقول الاستجابة ما حدث: رمز حالة (Status Code) مثل 201، وترويسات، وجسماً في الغالب.
وكلاهما نص منظّم تستطيع قراءته سطراً سطراً. أرسِل نموذج دعم فني، فقد يحمل الطلب {"subject": "Late delivery", "orderId": 9021}، وتجيب الاستجابة بـ201 Created ومعها التذكرة الجديدة في جسمها.
لماذا يهم
لا تعرض الشاشة إلا ما قررت الواجهة الأمامية عرضه: فقد تظهر عبارة «تم الحفظ» مع أن الخادم رفض البيانات. أما الطلب والاستجابة فيسجّلان ما جرى فعلاً بين العميل والخادم، فيكشفان هل العيب في العميل أم في الخادم أم فيهما معاً، ومن عليه إصلاحه.
الطلب: الطريقة والهدف والترويسات والجسم
في HTTP/1.1 (وفق RFC 9112) للطلب بنية ثابتة: سطر الطلب (Request Line)، ثم حقل ترويسة واحد في كل سطر، ثم سطر فارغ، ثم جسم اختياري. وينتهي سطر الطلب وكل سطر ترويسة بمحرفَي رجوع العربة والسطر الجديد (CRLF).
- الطريقة: الكلمة الأولى، وتسمّي الإجراء المطلوب، مثل
GETللقراءة أوPOSTلإرسال بيانات. ويتناول الدرس التالي كل طريقة. - هدف الطلب (Request Target): عادةً المسار مع سلسلة استعلام اختيارية، وهو هنا
/api/v1/tickets?lang=ar؛ أما اسم المضيف فيُرسل وحده في ترويسةHost. - إصدار البروتوكول:
HTTP/1.1يختم سطر الطلب. - حقول الترويسات: أسطر بصيغة
Name: value، مثلHost(المضيف المقصود بالطلب)، وContent-TypeوContent-Length(صيغة الجسم وحجمه)، وAcceptوAuthorization. ويجب أن يحمل طلب HTTP/1.1 ترويسةHostواحدة بالضبط، وإلا وجب على الخادم أن يجيب بـ400 Bad Request. - الجسم: كل ما بعد السطر الفارغ، ولا يوجد إلا حين تكون هناك بيانات للإرسال.
POST /api/v1/tickets?lang=ar HTTP/1.1
Host: support.example.com
Content-Type: application/json
Accept: application/json
Authorization: Bearer eyJhbGciOi...
Content-Length: 45
{"subject": "Late delivery", "orderId": 9021}الاستجابة: سطر الحالة والترويسات والجسم
يجيب الخادم بالبنية نفسها، ولا يختلف إلا السطر الأول: فسطر الحالة (Status Line) يحمل إصدار البروتوكول، ورمز حالة من ثلاثة أرقام، وعبارة السبب (Reason Phrase).
- رمز الحالة: النتيجة في صورة رقم. يتصرف العميل بناءً عليه، فهو ما تتحقق منه. والرقم الأول يحدد الفئة:
1xxمعلوماتية، و2xxنجاح، و3xxإعادة توجيه، و4xxمشكلة في الطلب، و5xxخطأ في الخادم. - عبارة السبب: نص للبشر مثل
Created. يطلب RFC 9112 من العملاء تجاهلها، وقد يصوغها كل خادم بطريقته، ولا يحملها HTTP/2 أصلاً؛ فلا تتحقق منها أبداً. - حقول الترويسات: معلومات عن الاستجابة، مثل صيغة الجسم وحجمه، و
Locationللمورد الجديد، وSet-CookieوCache-Control. - الجسم: البيانات المطلوبة، أو وصف لخطأ، أو لا شيء.
الطلب
الجزء 1:POST الجزء 2:/api/v1/tickets?lang=ar الجزء 3:HTTP/1.1 الجزء 6:Host: support.example.com Content-Type: application/json Accept: application/json Authorization: Bearer eyJhbGciOi... Content-Length: 45 الجزء 7: الجزء 8:{"subject": "Late delivery", "orderId": 9021}
الاستجابة
الجزء 3:HTTP/1.1 الجزء 4:201 الجزء 5:Created الجزء 6:Date: Thu, 01 Oct 2026 09:30:00 GMT Content-Type: application/json Content-Length: 62 Location: /api/v1/tickets/T-1047 الجزء 7: الجزء 8:{"id": "T-1047", "status": "open", "subject": "Late delivery"}
- 1–3سطر الطلب
- 3–5سطر الحالة
- 6–8متماثلة في الرسالتين
- 1الطريقة (Method)الإجراء المطلوب؛
POSTيرسل بيانات. ولكل طريقة قواعدها. - 2هدف الطلب (Request Target)المسار مع استعلام اختياري. أما اسم المضيف فيُرسل في ترويسة
Host. - 3إصدار البروتوكوليفتتح سطر الحالة ويختم سطر الطلب. ولا يضع HTTP/2 وHTTP/3 الإصدار في كل رسالة، بل يحدده الاتصال.
- 4رمز الحالةثلاثة أرقام، أولها يحدد الفئة. يتصرف العميل بناءً عليه، فتحقق منه.
- 5عبارة السببنص للبشر: يتجاهله العميل ولا يحمله HTTP/2. لا تتحقق منه أبداً.
- 6حقول الترويساتحقل
Name: valueفي كل سطر. الأسماء لا تميّز حالة الأحرف، وترتيب الحقول المختلفة لا معنى له. - 7السطر الفارغينهي قسم الترويسات: وكل ما بعده هو الجسم.
- 8الجسماختياري في الرسالتين.
Content-Typeتحدد صيغته، وContent-Lengthحجمه بالبايت.
النسخة النصية
HTTP/1.1 201 Created
Date: Thu, 01 Oct 2026 09:30:00 GMT
Content-Type: application/json
Content-Length: 62
Location: /api/v1/tickets/T-1047
{"id": "T-1047", "status": "open", "subject": "Late delivery"}جسم الطلب وجسم الاستجابة
يسمّي RFC 9110 الجسم «المحتوى» (Content)، وتسمّيه الأدوات الجسم أو الحمولة (Payload). وتحدد Content-Type صيغته بنوع وسائط (Media Type) مثل application/json لصيغة JSON، وهي صيغة نصية تستخدمها واجهات برمجية كثيرة وتضع الأسماء والقيم بين أقواس معقوفة. وتعطي Content-Length حجمه بالبايت، إلا إذا استخدم مُرسِل HTTP/1.1 الترويسة Transfer-Encoding: chunked وأرسل الجسم على دفعات.
- يحمل جسم الطلب البيانات التي تنشئها أو تغيّرها، لذا يوجد عادةً في طلبات
POSTوPUTوPATCH. أما طلباتGETوHEADوDELETEفلا جسم لها عادةً: فـRFC 9110 لا يعطي المحتوى فيها معنى معرّفاً بوجه عام. - يحمل جسم الاستجابة ما طلبته، مثل JSON أو HTML أو ملف، أو وصفاً لخطأ؛ ويعرّف RFC 9457 صيغة قياسية للأخطاء هي
application/problem+json(المثال أدناه). - بعض الاستجابات لا جسم لها أبداً: أي استجابة لطلب
HEAD، وكل استجابة1xxو204 No Contentو304 Not Modified. Content-Lengthتعدّ البايتات لا الأحرف. ففي UTF-8، وهو الترميز المعتاد الذي يحوّل نصوص الويب إلى بايتات، يأخذ كل حرف إنجليزي وكل رقم وكل علامة ترقيم بايتاً واحداً، وكل حرف عربي بايتين، وكل محرف من الديفاناغارية ثلاثة بايتات: فـ{"name": "سارة"}طوله 16 حرفاً لكنه 20 بايتاً.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
Content-Length: 132
{"type": "https://example.com/probs/missing-field", "title": "Missing field",
"status": 422, "detail": "subject must not be empty"}قراءة HTTP الخام
HTTP الخام هو الرسالة نصاً، كما في الأمثلة السابقة. في أدوات المطوّرين (DevTools) يحوي تبويب Headers في لوحة الشبكة (Network) مفتاح Raw، ويظهر جسم الطلب في تبويب Payload في Chrome أو Request في Firefox. ويضع الأمر curl -v العلامة > قبل سطر البداية وأسطر الترويسات التي أرسلها، و< قبل التي استقبلها. اقرأ بترتيب ثابت:
- سطر البداية: هل الطريقة والهدف هما ما قصده الاختبار؟ وفي الاستجابة خذ رمز الحالة لا عبارة السبب.
- الترويسات: أسماؤها لا تميّز حالة الأحرف، وترتيب الحقول المختلفة لا معنى له، فقارن الأسماء والقيم فقط.
- السطر الفارغ: قبله معلومات عن الرسالة، وبعده الجسم.
- المطابقة بين الأجزاء: رمز الحالة مقابل الجسم، و
Content-Typeمقابل الصيغة الفعلية للجسم، وContent-Lengthمقابل عدد بايتاته. فقد يبدو كل جزء سليماً وحده بينما يكون اجتماعها خاطئاً.
مثال تطبيقي: «تم الحفظ» لكن العنوان مفقود
يعرض تطبيق تسوّق عبارة «تم الحفظ» بعد أن يضيف المختبِر عنوان توصيل، لكن قائمة العناوين تبقى فارغة. ويقول توثيق الواجهة البرمجية إن الجسم يحتاج إلى city وpostalCode، وإن النجاح يعيد 201 Created، وخطأ التحقق من صحة البيانات يعيد 422 بجسم من نوع Problem Details. يكرر المختبِر الخطوة وأدوات المطوّرين مفتوحة، وينسخ التبادل.
- سطر الطلب والترويسات: كما في التوثيق؛
Content-Typeتطابق جسم JSON، وContent-Length: 42تساوي حجمه البالغ 42 بايتاً. - جسم الطلب:
postal_codeبدلاً منpostalCode. العيب الأول، في التطبيق. - سطر الحالة:
200 OKلحفظ لم يتم؛ فقد وثق التطبيق برمز2xxوعرض «تم الحفظ». العيب الثاني، في الواجهة البرمجية: المتوقع422. - ترويسات الاستجابة:
Content-Type: text/plainلجسم JSON. العيب الثالث، في الواجهة البرمجية: فالعميل الذي يتبع الترويسة قد لا يحلّل رسالة الخطأ. - جسم الاستجابة: يذكر الحقل الناقص، وهو ما دلّ على العيب الأول. ثلاثة عيوب، وجهتان مسؤولتان، وتبادل واحد.
POST /api/v1/customers/58/addresses HTTP/1.1
Host: api.example.com
Content-Type: application/json
Accept: application/json
Authorization: Bearer eyJhbGciOi...
Content-Length: 42
{"city": "Riyadh", "postal_code": "12271"}
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 53
{"success": false, "error": "postalCode is required"}أخطاء شائعة
- الحكم على النتيجة من الشاشة أو من رمز الحالة وحده: فاستجابة
200 OKتحمل خطأً في جسمها تمرّ دون أن يلاحظها أحد. - التحقق من عبارة السبب، أو من حالة أحرف الترويسات وترتيبها، بدلاً من رموز الحالة وقيم الترويسات.
- الوثوق بـ
Content-Typeلأن الجسم يبدو لك سليماً: فالعميل الذي يتبع الترويسة قد يعجز مع ذلك عن قراءته. - حساب
Content-Lengthبالأحرف: فالنص العربي والهندي والرموز التعبيرية تأخذ في UTF-8 بايتات أكثر من عدد أحرفها. - كتابة «فشل الطلب» دون إرفاق التبادل الخام، أو لصقه وفيه قيم
AuthorizationوCookieحقيقية بدلاً من إخفائها.
من منظور ضمان الجودة
اقرأ HTTP الخام كلما اختلفت الشاشة عن البيانات. افتح لوحة الشبكة قبل إعادة الخطوات، وابحث عن الطلب الذي يقف خلف الإجراء، واسأل سؤالين: هل أرسل العميل ما تطلبه المواصفات؟ وهل أجاب الخادم كما يقول توثيق الواجهة البرمجية؟
وفي تقرير الخطأ أرفق التبادل نصاً، أو أمر cURL مع الاستجابة، بعد إخفاء الرموز المميزة (Tokens)، وسمِّ الجزء الخاطئ: «المتوقع 422 بجسم Problem Details؛ والفعلي 200 OK مع Content-Type: text/plain». واطلب من فريق الواجهة البرمجية مبكراً رموز الحالة وصيغة الأخطاء لكل نقطة نهاية (Endpoint).
تمرين عملي
اقرأ تبادلين خامين واعثر على الخطأ
نُسخ التبادلان أدناه من بيئة Staging. حدّد أجزاء الرسائل الأربع، ثم افحص: هل يتفق كل رمز حالة مع جسمه؟ وهل تصف Content-Type الجسم؟ وهل تطابق Content-Length عدد بايتات الجسم؟
لكل مشكلة اكتب النتيجة المتوقعة والنتيجة الفعلية، وحدّد من عليه التغيير: العميل أم الخادم.
(1)
PUT /api/v1/profile HTTP/1.1
Host: app.example.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOi...
Content-Length: 23
{"displayName": "نورة"}
HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 70
{"error": "invalid_json", "message": "Request body is not valid JSON"}
(2)
DELETE /api/v1/profile/addresses/3 HTTP/1.1
Host: app.example.com
Authorization: Bearer eyJhbGciOi...
HTTP/1.1 204 No Content
Content-Type: application/json
Content-Length: 30
{"message": "Address deleted"}- حدّد سطر البداية وحقول الترويسات والسطر الفارغ والجسم في كل رسالة.
- قارن
Content-Typeبالصيغة الفعلية لكل جسم. - احسب بايتات كل جسم بأداة String Length Counter (بترميز UTF-8)، وقارنها بـ
Content-Length. - قارن كل رمز حالة بجسمه، ثم حدّد المسؤول عن كل مشكلة.
إظهار الإجابة النموذجية
الأجزاء: لكل رسالة سطر بداية وحقول ترويسات وسطر فارغ. لا جسم لطلب DELETE؛ وفي استجابة 204 بايتات بعد السطر الفارغ لا يجوز وجودها هناك (انظر التبادل 2)؛ وللرسالتين الأخريين جسم. وتعلن Content-Type صيغة JSON، وكل جسم هو JSON فعلاً، فلا يكشف هذا الفحص شيئاً.
التبادل (1): الجسم {"displayName": "نورة"} طوله 23 حرفاً لكنه 27 بايتاً، لأن كل حرف عربي يأخذ بايتين في UTF-8. أعلن العميل Content-Length: 23، فقرأ الخادم {"displayName": "نور فقط ورفضه عن حق لأنه JSON غير صالح؛ واستجابته 400 متسقة (70 بايتاً كما أُعلن). العيب في العميل الذي يعدّ الأحرف بدلاً من البايتات، ولن يظهر أبداً في اختبار باسم إنجليزي.
التبادل (2): لا جسم لطلب DELETE، وهذا صحيح. لكن استجابة 204 No Content لا يجوز أن تحتوي محتوى (RFC 9110)، ولا أن يُرسل معها Content-Length. ويَعُدّ العميل الاستجابة منتهية عند السطر الفارغ، فلا تظهر الرسالة أبداً، وعلى اتصال HTTP/1.1 مُعاد استخدامه قد تُقرأ البايتات الثلاثون الزائدة على أنها الاستجابة التالية. وعلى الخادم أن يرسل 204 دون شيء بعد السطر الفارغ، أو 200 OK مع الجسم.
أسئلة شائعة
هل أحتاج إلى معرفة HTTP/2 وHTTP/3 لقراءة الطلبات والاستجابات؟
لا. يرسل HTTP/2 وHTTP/3 الأجزاء نفسها (الطريقة والهدف ورمز الحالة وحقول الترويسات والجسم) في إطارات ثنائية بدلاً من أسطر نصية، ويعرّف RFC 9110 معناها في كل الإصدارات. وتعرضها الأدوات بصيغة مقروءة؛ فتوقّع أسماء ترويسات بأحرف صغيرة، وترويسات زائفة (Pseudo-headers) مثل :method و:path، وغياب عبارة السبب.
هل الجسم والحمولة والمحتوى شيء واحد؟
في الاستخدام اليومي نعم: البيانات التي تلي قسم الترويسات. يسمّيها RFC 9110 المحتوى (Content)، ويسمّي RFC 9112، الذي يعرّف صيغة HTTP/1.1 النصية، البايتاتِ المنقولة جسمَ الرسالة (Message Body)، ويختلف عن المحتوى إذا طُبّق ترميز نقل مثل chunked. وكثير من الأدوات يقول Payload.
هل يمكن أن يكون لطلب GET جسم؟
يمكن أن تحمل الرسالة جسماً، لكن RFC 9110 لا يعطي المحتوى في طلب GET معنى معرّفاً بوجه عام، وقد تتجاهله الخوادم والوسطاء (Proxies) وذواكر التخزين المؤقت أو ترفضه. ضع مدخلات GET في سلسلة الاستعلام، وإذا وثّقت واجهة برمجية جسماً لطلب GET فاعتبره خطراً واختبره عبر كل عميل ووسيط مستخدَم.
المراجع
- RFC 9110: HTTP Semanticsمعاني أساليب HTTP وحقول الترويسات ورموز الحالة والتفاوض على المحتوى، بغضّ النظر عن إصدار البروتوكول.
- RFC 9112: HTTP/1.1صياغة رسائل HTTP/1.1: سطر الطلب وحقول الترويسات والنقل المجزّأ ومعالجة الاتصال.
- RFC 9457: Problem Details for HTTP APIsصيغة الخطأ application/problem+json (type وtitle وstatus وdetail وinstance) لأخطاء API القابلة للقراءة آلياً.
- Overview of HTTP — MDNكيف يعمل HTTP: بروتوكول عميل–خادم عديم الحالة، يرسل فيه العميل طلباً ويردّ الخادم برسالة استجابة.
تدرّب بأدوات متقن
تحليل ترويسات طلبات واستجابات HTTP الخام إلى جدول منظّم مع الشروحات.
اطّلع بالضبط على ما يرسله عميلك: الطريقة والترويسات والاستعلام والجسم وعنوان IP ومعلومات TLS.
أنشئ طلبات HTTP وأرسلها (الطريقة وعنوان URL والترويسات والمصادقة والجسم) وافحص الاستجابة — بديل خفيف لـ Postman داخل متصفحك.
التحقق من صحة ترويسات Content-Type والتأكد من أن متن الاستجابة يطابق فعلاً نوع الوسائط المعلن.
قِس طول السلسلة النصية بالأحرف ونقاط الترميز (code points) وبايتات UTF-8 ووحدات UTF-16.
ابحث عن أي رمز حالة HTTP لمعرفة معناه ومرجعه في RFC ومتى يُستخدم.
للتعمّق أكثر
تقدّمك في هذا الموضوع
سجّل الدخول لتتابع تقدّمك
علّم الموضوعات مكتملة، وتابع من حيث توقفت، وافتح امتحانات التخصص.