شرح صفوف ومحتوى الفقرة
تخيّل أنك تكتب قائمة مشتريات على ورقة، ثم تترك سطراً فارغاً قبل كتابة ملاحظة للمندوب؛ هذا السطر الفارغ يخبر القارئ فوراً أن القائمة انتهت وبدأ كلام جديد. في رسائل HTTP/1.1، يؤدي السطر الفارغ الفاصل نفس الدور بالضبط: يقع بعد آخر رأس من رؤوس الرسالة وقبل بداية الجسم مباشرةً ليخبر السيرفر أو المتصفح أن «رؤوس الرسالة انتهت هنا، وكل ما يأتي بعد هذا السطر هو محتوى الجسم».
في الكمبيوتر، عندما تضغط مفتاح Enter للانتقال إلى سطر جديد في رسائل HTTP، يضع البروتوكول رمزين غير مرئيين لنهاية السطر يُرمَز لهما بالاختصار CRLF (ويُكتبان برمجياً \r\n). ولأن آخر رأس في الرسالة ينتهي أصلاً بنزول سطر CRLF، فإن ترك سطر فارغ إضافي بعده يعني ضغط Enter مرتين متتاليتين (\r\n\r\n) كما يوضح المثال الآتي:
# 1. Visual representation of CRLF (\r\n) in a bodiless GET request:
GET /courses/http HTTP/1.1\r\n
Host: closetag.com\r\n
Accept-Language: ar, en\r\n
\r\n
# 2. Raw stream view showing Double CRLF (\r\n\r\n) at the end:
# ...Accept-Language: ar, en\r\n\r\n
# ^^^^---- Ends the last header line
# ^^^^ Standalone Blank Line (CRLF)
بمجرد أن يقرأ السيرفر أو المتصفح هذا السطر الفارغ (\r\n\r\n)، يتوقف فوراً عن البحث عن رؤوس جديدة:
- إذا كانت الرسالة بدون جسم (مثل طلب
GETعادي لجلب صفحة): فإن السطر الفارغ يعلن نهاية الرسالة بالكامل ويبدأ السيرفر في الرد فوراً. - إذا كانت الرسالة تحتوي على جسم (مثل إرسال بيانات أو استقبال صفحة
HTML): يقرأ المستقبِل محتوى الجسم بعد السطر الفارغ بعدد البايتات المكتوب في رأس الطولContent-Length. ولهذا السبب، لو كان داخل كودHTMLأوJSONفي الجسم عشرات الأسطر الفارغة، فلن يتلخبط المتصفح أبداً لأنه عبر مرحلة الرؤوس بالفعل كما يظهر في المثال الآتي:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 77
<-- 1st Blank Line: Ends Header Section
<!DOCTYPE html>
<html>
<-- Blank line inside Body (normal text)
<body>
<h1>Welcome to CloseTag</h1>
</body>
</html>
ويشترط معيار HTTP أن يكون السطر الفارغ الفاصل خالياً تماماً من أي مسافات بيضاء أو علامات جدولة قبل فاصل CRLF. فوجود مسافة في بداية السطر لا يُعد سطراً فارغاً في قواعد البروتوكول، بل يُصنف تركيباً غير قياسي مرفوضاً. كما أن إسقاط السطر الفارغ قبل الجسم يجعل المحلل يدمج أول سطر من الجسم مع قسم الرؤوس ويحاول قراءته كرأس. ويؤدي ذلك إلى فشل التحليل أو رفض الرسالة برمز خطأ العميل 400 Bad Request، لذا يُعد فهمه مهارة أساسية في بناء الأنظمة وتشخيص الشبكات.
تفصيل تقني متقدم: الاتصالات المستمرة (Connection Persistence) ومصافحة 100 Continue قبل رفع الأجسام الكبيرة
تظهر الأهمية القصوى للسطر الفارغ CRLF وتأطير الرسائل في خاصيتين معياريتين في HTTP/1.1:
- الاتصالات المستمرة الافتراضية (Connection Persistence —
RFC 9112 §9.3): يُبقيHTTP/1.1اتصالTCPمفتوحاً افتراضياً (Keep-Alive) لإرسال عدة طلبات واستجابات متتالية عبر المقبس نفسه دون إغلاقه؛ وبفضل السطر الفارغCRLFوطول الجسم الدقيق، يعرف المحلل أين تنتهي الرسالة الأولى وأين يبدأ سطر البداية للرسالة الثانية فوراً، ولا يُغلق الاتصال إلا عند إرسال الرأسConnection: close. - الاستجابة المؤقتة
100 Continue(RFC 9110 §10.1.1 & §15.2.1): عندما يعتزم العميل رفع جسم رسالة ضخم ويخشى أن يرفض الخادم الطلب بسبب الصلاحيات أو الحجم، يرسل العميل رأس الطلب فقط متبوعاً بالسطر الفارغCRLFمع رأسExpect: 100-continueوينتظر؛ فإذا وافق الخادم ردّ باستجابة إعلامية مؤقتة خالية من الجسمHTTP/1.1 100 Continue\r\n\r\n، وحينئذٍ فقط يبث العميل بايتات الجسم على الاتصال نفسه.
# A) Persistent TCP Connection (2 requests on the same socket)
GET /app.css HTTP/1.1
Host: www.closetag.com
# Next request on the SAME TCP connection (then close):
GET /app.js HTTP/1.1
Host: www.closetag.com
Connection: close
# B) 100 Continue Flow (Head sent first -> Server approves -> Body sent)
PUT /backups/db-dump.sql HTTP/1.1
Host: storage.closetag.com
Content-Length: 52428800
Expect: 100-continue
# <-- Server replies: HTTP/1.1 100 Continue\r\n\r\n
# --> Client now streams the 50 MB body on the same TCP connection