أساسيات الشبكات لـ DevOps

HTTP و HTTPS للمشغّلين

18 دقيقة الدرس 4 من 30

HTTP و HTTPS للمشغّلين

HTTP هو البروتوكول الذي يُحرّك الويب. بوصفك مهندس DevOps، لن تكتب منطق التطبيق، لكنّك أنت من يشخّص سبب استغراق الطلب 8 ثوانٍ، ولماذا يُعيد موزّع الحِمل 502 عند ذروة الحمل، أو ما الذي يُسبّب حلقة إعادة توجيه تُعطّل عملية النشر. هذا يستلزم فهماً دقيقاً على مستوى المشغّل لآلية عمل HTTP من البداية إلى النهاية: الأساليب، ورموز الحالة، والترويسات، ودورة حياة الاتصال، وإصدارات البروتوكول.

نموذج الطلب-الاستجابة

كل تبادل HTTP هو عبارة عن طلب يُرسله العميل، واستجابة يُعيدها الخادم. في HTTP/1.1 كلاهما نص عادي: سطر بداية، ثم ترويسات، ثم سطر فارغ، ثم جسم اختياري. فهم هذا البناء يُمكّنك من قراءة حركة المرور الخام في tcpdump أو wireshark دون الحاجة إلى أدوات متخصصة.

HTTP Request-Response cycle Client Browser / curl Server nginx / app REQUEST GET /api/users HTTP/1.1 | Host: api.example.com | Accept: application/json RESPONSE HTTP/1.1 200 OK | Content-Type: application/json | {"users":[...]}
دورة الطلب-الاستجابة في HTTP: يُرسل العميل طلباً مُهيكلاً؛ يُعيد الخادم سطر الحالة والترويسات والجسم الاختياري.

أساليب HTTP — عقود تعتمد عليها البنية التحتية

لكل أسلوب عقد محدد من حيث السلامة (هل يغيّر الحالة؟) والقابلية للتكرار (هل إعادة تنفيذه آمنة؟). تعتمد موازنات الحِمل والذاكرة التخزينية ومنطق إعادة المحاولة على هذه العقود. كسرها يُفضي إلى طلبات مُكررة، أو فواتير مُضاعفة، أو تلف صامت للبيانات.

  • GET — آمن وقابل للتكرار. يسترجع موردًا. قابل للتخزين المؤقت دائماً ما لم يُحدَّد خلاف ذلك. لا تستخدم GET أبداً لإطلاق تغيير في الحالة.
  • POST — غير آمن وغير قابل للتكرار. يُنشئ أو يُرسل. إعادة محاولة POST عشوائياً قد تُنشئ سجلات مُكررة؛ استخدم مفاتيح المعرّف الفريد (UUID في ترويسة) لجعل إعادة المحاولة آمنة على نطاق واسع.
  • PUT — غير آمن، لكنه قابل للتكرار. يستبدل المورد كاملاً عند URL محدد. آمن لإعادة المحاولة عند انتهاء المهلة.
  • PATCH — غير آمن، وغير قابل للتكرار عادةً. تحديث جزئي. عامله معاملة POST من حيث إعادة المحاولة ما لم يُطبّق الخادم عقد التكرار صراحةً.
  • DELETE — غير آمن، قابل للتكرار. حذف مورد مرتين يجب أن يُعيد 404 في المرة الثانية، لا خطأً. إعادة المحاولة عند انتهاء المهلة آمنة.
  • HEAD — مطابق لـ GET لكن بلا جسم. استخدمه للتحقق من وجود مورد أو قراءة ترويسات مثل Content-Length دون تنزيل المحتوى.
  • OPTIONS — يُعيد الأساليب التي يدعمها الخادم. تُطلقه المتصفحات تلقائياً قبل كل طلب عبر النطاقات (CORS preflight).

رموز الحالة المهمة في بيئة الإنتاج

احفظ هذه المجموعات جيداً. كل تنبيه مراقبة، ولوحة SLO، وتقرير حادثة يستند إليها.

  • 2xx نجاح: 200 OK، 201 Created (POST أنشأ موردًا — يجب أن يتضمن الجسم ترويسة Location204 No Content (نجاح بلا جسم — شائع مع DELETE)، 206 Partial Content (طلبات النطاق، بث الفيديو).
  • 3xx إعادة توجيه: 301 Moved Permanently (يُخزّنه المتصفح إلى الأبد — استخدمه فقط حين لن يعود URL القديم أبداً)، 302 Found (مؤقت، لا يُخزَّن)، 307/308 (مثل 302/301 لكنهما يحتفظان بأسلوب HTTP — الأفضل لإعادة توجيه API كي يبقى POST كما هو).
  • 4xx خطأ العميل: 400 Bad Request، 401 Unauthorized (بيانات اعتماد مفقودة أو غير صالحة)، 403 Forbidden (مُصادق عليه لكن غير مُصرح)، 404 Not Found، 408 Request Timeout، 429 Too Many Requests (أرفق دائماً ترويسة Retry-After499 (خاص بـ nginx: العميل أغلق الاتصال قبل استلام الاستجابة).
  • 5xx خطأ الخادم: 500 Internal Server Error، 502 Bad Gateway (المصدر أعاد استجابة غير صالحة — غالباً التطبيق انهار)، 503 Service Unavailable (استخدمه أثناء النشر المتدرج)، 504 Gateway Timeout (المصدر لم يستجب ضمن المهلة).
ممارسة احترافية: افصل 5xx عن 4xx في التنبيهات وميزانيات الخطأ. ارتفاع 5xx المستمر يكسر SLO التوفر — نبّه فوراً. ارتفاع 4xx عادةً خطأ عميل — نبّه بتدرج أكبر. ارتفاع مفاجئ في 404 يعني في الغالب أن نشراً فاسداً غيّر نمط URLs؛ ارتفاع 401 يعني أن تدوير رمز مصادقة لم يُطبَّق في كل مكان.

الترويسات — مستوى التحكم في HTTP

الترويسات تحمل البيانات الوصفية التي تتحكم في التخزين المؤقت، والمصادقة، والتوجيه، والتفاوض على المحتوى، والأمان. هذه هي الترويسات التي ستقرأها وتضبطها باستمرار بوصفك مشغّلاً:

  • Host — مطلوب في HTTP/1.1. يُخبر الخادم بالمضيف الافتراضي المطلوب. يستخدمها nginx للمطابقة مع server_name؛ قيمة خاطئة أو مفقودة تضرب الخادم الافتراضي.
  • Content-Type — نوع MIME لجسم الطلب أو الاستجابة. اضبطها صراحةً دائماً في الطلبات. حذفها يجعل الخادم يخمّن الترميز، وكثيراً ما يُخطئ.
  • Authorization — تحمل بيانات الاعتماد: Bearer <token> لـ JWTs وOAuth 2.0، Basic <base64(user:pass)> للمصادقة الأساسية (فقط عبر HTTPS).
  • Cache-Controlno-store (لا تُخزّن في أي مكان)، no-cache (مُخزَّن لكن يجب إعادة التحقق قبل الاستخدام)، max-age=3600 (خزّن لساعة)، s-maxage=86400 (مدة CDN تتجاوز max-age للذاكرات المشتركة).
  • X-Forwarded-For — تضيفها البروكسيات بعنوان IP العميل الأصلي. تحقق من أن الـ ingress يُزيل القيم التي يُدخلها المهاجمون قبل إضافة قيمته الخاصة، وإلا يمكن تزوير الـ IP لتجاوز تحديد المعدل.
  • Transfer-Encoding: chunked — الجسم يُرسل في أجزاء متغيرة الحجم بلا Content-Length. مطلوب للاستجابات المتدفقة حين يكون الحجم الكلي مجهولاً عند بدء الإرسال.

Keep-Alive وإعادة استخدام الاتصال

فتح اتصال TCP يكلّف رحلة ذهاب وإياب واحدة (50-100 ملي ثانية في شبكات WAN النموذجية). إضافة TLS تزيد رحلة أو رحلتين. الاتصالات الدائمة (keep-alive) تُتيح تبادلات HTTP متعددة عبر نفس اتصال TCP، مما يُوزّع هذه التكلفة على طلبات كثيرة. هذا هو الوضع الافتراضي في HTTP/1.1 وإلزامي في HTTP/2.

حين يعمل nginx كبروكسي عكسي، يجب ضبط keep-alive للمصادر صراحةً، وإلا يفتح كل طلب اتصال TCP جديداً — اختناق خطير في الإنتاجية ومصدر شائع لارتفاعات 502 عند موجات الحمل.

# /etc/nginx/conf.d/api.conf — بروكسي عكسي مع upstream keep-alive upstream app_servers { server 10.0.1.10:8080; server 10.0.1.11:8080; keepalive 64; # احتفظ بـ 64 اتصالاً خاملاً لكل عامل نحو المصادر } server { listen 443 ssl http2; server_name api.example.com; keepalive_timeout 65; # انتظر 65 ث للطلب التالي قبل إغلاق اتصال العميل keepalive_requests 1000; # الحد الأقصى للطلبات عبر اتصال keep-alive واحد location /api/ { proxy_pass http://app_servers; proxy_http_version 1.1; # مطلوب لـ upstream keep-alive proxy_set_header Connection ""; # أزل ترويسة hop-by-hop — ضروري proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 5s; proxy_read_timeout 30s; } }
فخ إنتاجي: التفاوت في مهلة keep-alive يُسبّب أخطاء 502 متقطعة. موزّع الحِمل يُبقي اتصالاً خاملاً 60 ثانية ثم يُعيد استخدامه؛ لكن خادم التطبيق أغلقه بعد 55 ثانية. الطلب الأول على هذا الاتصال الميت يفشل. الحل: اضبط مهلة خمول موزّع الحِمل أعلى من مهلة keepalive الخادم بقليل، حتى يُغلق الخادم الاتصال دائماً أولاً. AWS ALB افتراضياً 60 ث — اضبط keepalive_timeout في nginx على 55 ث حين تعمل خلفه.

HTTP/2 و HTTP/3 — ما الذي تغيّر للمشغّلين

HTTP/2 يعمل عبر اتصال TLS واحد ويُعالج طلبات واستجابات كثيرة بالتوازي كـتدفقات مستقلة، مما يُزيل ظاهرة head-of-line blocking على مستوى التطبيق. يستخدم إطارات ثنائية بدلاً من النص العادي ويضغط الترويسات بـ HPACK، مما يُقلل الحِمل للـ APIs التي ترسل طلبات صغيرة كثيرة بترويسات متكررة.

HTTP/1.1 vs HTTP/2 multiplexing HTTP/1.1 3 connections, sequential Req 1 Wait... Resp 1 Req 2 Wait... Resp 2 Req 3 Wait... Resp 3 HTTP/2 1 connection, multiplexed streams Req 1 Req 2 Req 3 Single TLS connection (multiplexed) Resp 1 Resp 2 Resp 3 time
HTTP/1.1 يحتاج اتصالات منفصلة وطلبات متسلسلة؛ HTTP/2 يُعالج جميع التدفقات عبر اتصال TLS واحد.

أهم ما يعنيك كمشغّل في HTTP/2:

  • TLS إلزامي فعلياً (جميع المتصفحات الكبرى تشترطه لـ HTTP/2).
  • تقسيم النطاق (استخدام cdn1.example.com وcdn2.example.com لفتح اتصالات أكثر) كان حلاً مؤقتاً لـ HTTP/1.1 — وهو يُضرّ فعلياً بـ HTTP/2 لأنه يُشتّت التدفق المُحسَّن الواحد.
  • فعّل HTTP/2 في nginx بـ listen 443 ssl http2;. اتصالات المصادر داخلياً يمكن أن تبقى HTTP/1.1.

HTTP/3 يستبدل TCP بـ QUIC (مبني على UDP)، مما يُزيل head-of-line blocking على مستوى TCP أيضاً. مصافحة TLS مدمجة في مصافحة QUIC، مما يُتيح استئنافاً بصفر رحلات (0-RTT) للزوار المتكررين. nginx 1.25+ يدعم HTTP/3. للمشغّلين اليوم، تفعيله على مستوى CDN كافٍ — دع الـ CDN يتفاوض على HTTP/3 مع المتصفحات بينما مصدرك يتحدث HTTP/1.1 أو HTTP/2.

تشخيص HTTP بـ curl — الأداة الأولى للمشغّل

curl هي أداتك التشخيصية الأولى لأي مشكلة HTTP. هذه الأعلام تُمكّنك من محاكاة أي طلب يصدره متصفح أو خدمة، وقياس أين تذهب كل ميلي ثانية.

# 1. عرض ترويسات الطلب والاستجابة كاملةً — الأكثر فائدةً curl -v https://api.example.com/health # 2. تتبع إعادة التوجيه وعرض URL النهائي curl -L -v https://example.com/old-path # 3. POST بجسم JSON وترويسة مصادقة curl -X POST https://api.example.com/users \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ -d '{"name":"ops-test","email":"ops@example.com"}' # 4. قياس كل مرحلة بدقة — أساسي لتحليل الكُمون curl -o /dev/null -s -w \ "dns:%{time_namelookup}s tcp:%{time_connect}s tls:%{time_appconnect}s ttfb:%{time_starttransfer}s total:%{time_total}s\n" \ https://api.example.com/health # 5. تجاوز DNS — اختبار خادم بعينه قبل تحويل DNS (اختبار الكناري) curl --resolve api.example.com:443:10.0.1.42 \ https://api.example.com/health # 6. فحص ترويسات الاستجابة فقط (بلا تنزيل جسم) curl -I https://example.com/ # 7. فرض HTTP/2 صراحةً curl --http2 -v https://api.example.com/ # 8. فحص سلسلة إعادة التوجيه دون اتباعها curl -D - -o /dev/null -L --max-redirs 0 https://example.com/old # 9. ترويسة Host مخصصة — اختبار Virtual Host أو خادم بعينه curl -H "Host: staging.internal.example.com" https://10.0.1.50/health
فكرة محورية: تفكيك التوقيت بالعَلَم -w يُخبرك فوراً أين يقضي الطلب البطيء وقته. time_namelookup مرتفع يعني DNS هو العائق. الفرق بين time_appconnect وtime_connect مرتفع يعني مصافحة TLS بطيئة (سلسلة شهادات طويلة، أو OCSP stapling مفقود). time_starttransfer مرتفع بعد time_appconnect يعني التطبيق نفسه بطيء في توليد البايت الأول. كل رقم يشير إلى حل مختلف.

HTTPS — ما الذي يتغيّر للمشغّلين

HTTPS هو HTTP ينقل عبر TLS. من منظور HTTP لا شيء يتغير — نفس الأساليب والرموز والترويسات. ما يتغير هو أن اتصال TCP يحمل الآن قناة مُشفَّرة مُوثَّقة. ثلاثة موضوعات خاصة بـ HTTPS يجب أن تعرفها (تُغطَّى بعمق في الدرس التالي عن TLS):

  • المنفذ — HTTPS يعمل على المنفذ 443 افتراضياً. HTTP على 80. أعد دائماً توجيه 80 إلى 443 بـ 301، واضبط ترويسة HSTS على استجابة HTTPS: Strict-Transport-Security: max-age=31536000; includeSubDomains لتجعل المتصفحات تتجاوز HTTP في الزيارات اللاحقة.
  • المحتوى المختلط — صفحة تُقدَّم عبر HTTPS لكنها تُحمّل موردًا فرعياً (صورة، سكريبت، CSS) عبر HTTP يُصنّفها المتصفح كمحتوى مختلط وقد يحجبه. يمكن لبروكسيك إرسال Content-Security-Policy: upgrade-insecure-requests لإجبار المتصفح على ترقية جميع الطلبات الفرعية إلى HTTPS تلقائياً.
  • أخطاء الشهادات — استجابة curl تقول SSL certificate problem تعني أن سلسلة الشهادات مكسورة، أو منتهية الصلاحية، أو أن اسم المضيف لا يتطابق. استخدم دائماً curl -v لرؤية الشهادة المُقدَّمة. استخدم --cacert /path/to/ca.pem للوثوق بـ CA خاصة في السكريبتات الآلية بدلاً من العَلَم الخطير -k (تجاوز التحقق).