طلبات 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}

جرّبها: منشئ طلبات API

الاستجابة: سطر الحالة والترويسات والجسم

يجيب الخادم بالبنية نفسها، ولا يختلف إلا السطر الأول: فسطر الحالة (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. 1الطريقة (Method)الإجراء المطلوب؛ POST يرسل بيانات. ولكل طريقة قواعدها.
  2. 2هدف الطلب (Request Target)المسار مع استعلام اختياري. أما اسم المضيف فيُرسل في ترويسة Host.
  3. 3إصدار البروتوكوليفتتح سطر الحالة ويختم سطر الطلب. ولا يضع HTTP/2 وHTTP/3 الإصدار في كل رسالة، بل يحدده الاتصال.
  4. 4رمز الحالةثلاثة أرقام، أولها يحدد الفئة. يتصرف العميل بناءً عليه، فتحقق منه.
  5. 5عبارة السببنص للبشر: يتجاهله العميل ولا يحمله HTTP/2. لا تتحقق منه أبداً.
  6. 6حقول الترويساتحقل Name: value في كل سطر. الأسماء لا تميّز حالة الأحرف، وترتيب الحقول المختلفة لا معنى له.
  7. 7السطر الفارغينهي قسم الترويسات: وكل ما بعده هو الجسم.
  8. 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"}

جرّبها: مرجع رموز حالة HTTP

جسم الطلب وجسم الاستجابة

يسمّي 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"}

جرّبها: مدقّق Content-Type جرّبها: عدّاد طول السلاسل النصية

قراءة HTTP الخام

HTTP الخام هو الرسالة نصاً، كما في الأمثلة السابقة. في أدوات المطوّرين (DevTools) يحوي تبويب Headers في لوحة الشبكة (Network) مفتاح Raw، ويظهر جسم الطلب في تبويب Payload في Chrome أو Request في Firefox. ويضع الأمر curl -v العلامة > قبل سطر البداية وأسطر الترويسات التي أرسلها، و< قبل التي استقبلها. اقرأ بترتيب ثابت:

  • سطر البداية: هل الطريقة والهدف هما ما قصده الاختبار؟ وفي الاستجابة خذ رمز الحالة لا عبارة السبب.
  • الترويسات: أسماؤها لا تميّز حالة الأحرف، وترتيب الحقول المختلفة لا معنى له، فقارن الأسماء والقيم فقط.
  • السطر الفارغ: قبله معلومات عن الرسالة، وبعده الجسم.
  • المطابقة بين الأجزاء: رمز الحالة مقابل الجسم، وContent-Type مقابل الصيغة الفعلية للجسم، وContent-Length مقابل عدد بايتاته. فقد يبدو كل جزء سليماً وحده بينما يكون اجتماعها خاطئاً.

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

مثال تطبيقي: «تم الحفظ» لكن العنوان مفقود

يعرض تطبيق تسوّق عبارة «تم الحفظ» بعد أن يضيف المختبِر عنوان توصيل، لكن قائمة العناوين تبقى فارغة. ويقول توثيق الواجهة البرمجية إن الجسم يحتاج إلى 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"}
الخطوات
  1. حدّد سطر البداية وحقول الترويسات والسطر الفارغ والجسم في كل رسالة.
  2. قارن Content-Type بالصيغة الفعلية لكل جسم.
  3. احسب بايتات كل جسم بأداة String Length Counter (بترميز UTF-8)، وقارنها بـContent-Length.
  4. قارن كل رمز حالة بجسمه، ثم حدّد المسؤول عن كل مشكلة.
إظهار الإجابة النموذجية
الإجابة النموذجية

الأجزاء: لكل رسالة سطر بداية وحقول ترويسات وسطر فارغ. لا جسم لطلب 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 SemanticsIETF · 2022معاني أساليب HTTP وحقول الترويسات ورموز الحالة والتفاوض على المحتوى، بغضّ النظر عن إصدار البروتوكول.
  • RFC 9112: HTTP/1.1IETF · 2022صياغة رسائل HTTP/1.1: سطر الطلب وحقول الترويسات والنقل المجزّأ ومعالجة الاتصال.
  • RFC 9457: Problem Details for HTTP APIsIETF · 2023صيغة الخطأ application/problem+json (type وtitle وstatus وdetail وinstance) لأخطاء API القابلة للقراءة آلياً.
  • Overview of HTTP — MDNMDN Web Docs (Mozilla)كيف يعمل HTTP: بروتوكول عميل–خادم عديم الحالة، يرسل فيه العميل طلباً ويردّ الخادم برسالة استجابة.

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

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

الويب

اطّلع بالضبط على ما يرسله عميلك: الطريقة والترويسات والاستعلام والجسم وعنوان IP ومعلومات TLS.

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

أنشئ طلبات HTTP وأرسلها (الطريقة وعنوان URL والترويسات والمصادقة والجسم) وافحص الاستجابة — بديل خفيف لـ Postman داخل متصفحك.

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

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

الويب

ابحث عن أي رمز حالة HTTP لمعرفة معناه ومرجعه في RFC ومتى يُستخدم.

الويب

للتعمّق أكثر

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

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