أفضل ممارسات الشبكات
أفضل ممارسات الشبكات
معرفة كيفية فتح مقبس أو إرسال طلب HTTP ليست سوى نصف العمل. يجب على كود الشبكات الاحترافي أن يصمد أمام حقائق الأنظمة الموزّعة: الخوادم البطيئة، والأعطال المؤقتة، واستنزاف مجمّعات الاتصال، وهجمات الوسيط. يُلخّص هذا الدرس الركائز الأربع التي تُميّز كود الشبكات على مستوى الإنتاج عن الكود التجريبي: المهلات الزمنية، وإعادة المحاولة مع التراجع التدريجي، وإعادة استخدام الاتصال، وأساسيات TLS.
١. المهلات الزمنية — اضبطها دائمًا
يمكن لأي استدعاء شبكي أن يُحجب إلى الأبد ما لم تُحدّد له حدًّا زمنيًا صريحًا. يعرض HttpClient في Java نوعين مستقلّين من المهلات:
- مهلة الاتصال — المدة التي ينتظرها البرنامج لاكتمال مصافحة TCP. تُضبط على مستوى
HttpClientنفسه. - مهلة الطلب — المدة الإجمالية المسموح بها لدورة الطلب/الاستجابة كاملةً. تُضبط لكل
HttpRequestعلى حدة.
إذا انتهت مهلة الاتصال تحصل على ConnectException، وإذا انتهت مهلة الطلب تحصل على HttpTimeoutException. التعامل معهما بشكل منفصل ضروري — فانتهاء المهلة إشارة قابلة للمعالجة، وليس خطأً قاتلًا.
٢. إعادة المحاولة مع التراجع الأسّي
الأعطال المؤقتة — انقطاع DNS العابر، أو استجابة 503 Service Unavailable، أو اتصال TCP مقطوع — أمر طبيعي في الأنظمة الموزّعة. الاستجابة الصحيحة هي حلقة إعادة محاولة محدودة مع تراجع أسّي وعشوائية إضافية.
لماذا التراجع الأسّي؟ إذا كان الخادم مثقلًا وأعادت جميع العملاء المحاولة في آنٍ واحد بفاصل زمني ثابت، فإنها تُنشئ قطيعًا مندفعًا يُفاقم الوضع. مضاعفة وقت الانتظار مع كل محاولة يوزّع الحمل. إضافة عشوائية تمنع عواصف إعادة المحاولة المتزامنة حتى حين تبدأ جميع العملاء في الوقت ذاته.
GET أو DELETE آمنة للإعادة. أما POST الذي يُنشئ موردًا فلا — إعادة تشغيله قد تُضاعف البيانات. للعمليات غير الآمنة للتكرار، استخدم مفاتيح التفرّد (أرسل ترويسة Idempotency-Key فريدة يستخدمها الخادم للتحقق من التكرار).
احترم أيضًا ترويسة الاستجابة Retry-After عند وجودها — فالخوادم التي تُعيد 429 Too Many Requests غالبًا تُخبرك بالمدة التي يجب الانتظار فيها. حلّل تلك الترويسة واستخدم قيمتها بدلًا من قيمة التراجع الخاصة بك.
٣. إعادة استخدام الاتصال — مجمّع اتصالات HttpClient
فتح اتصال TCP مُكلف: يتطلّب مصافحة ثلاثية الاتجاه، وإذا كان TLS متضمّنًا، تضاف 1–2 رحلة ذهاب وإياب إضافية للمصافحة. إنشاء HttpClient جديد مع كل طلب يُهدر هذا الاستثمار في كل مرة.
يحتفظ HttpClient في Java بمجمّع اتصالات داخلي تلقائيًا حين تُعيد استخدام نفس النسخة. يدعم المجمّع كلًا من keep-alive في HTTP/1.1 وتعدّد الإرسال في HTTP/2 (طلبات متعددة عبر اتصال واحد).
HttpClient جديدًا داخل حلقة أو في كل استدعاء طلب. كل نسخة تبدأ بمجمّع اتصالات فارغ، لذا تدفع التكلفة الكاملة لبناء الاتصال في كل مرة وقد تستنزف مقابض الملفات تحت الحمل.
في أطر العمل مثل Spring Boot، تُحقن HttpClient المشترك كـ bean (أو تستخدم RestClient / WebClient التي تدير مجامعها الخاصة). المبدأ واحد: مجمّع واحد لكل خدمة علوية.
٤. أساسيات TLS — الثقة والشهادات والتحقق من اسم المضيف
يُطبّق HttpClient في Java TLS بشكل افتراضي لعناوين https://. فهم ما يجري خلف الكواليس يساعدك على معالجة الحالات التي تحتاج فيها الإعدادات الافتراضية إلى ضبط.
- مخزن الثقة — يأتي JVM مزوّدًا بمخزن ثقة
cacertsيحتوي على شهادات CA المعروفة. عند اتصال عميلك، يُقدّم الخادم سلسلة شهاداته؛ يتحقق JVM من أنها ترتبط بـ CA موثوق وأن الشهادة لم تنتهِ صلاحيتها. - التحقق من اسم المضيف — بعد إثبات الثقة، يتحقق JVM من أن اسم المضيف في URL يطابق
Subject Alternative Name(أوCN) في الشهادة. هذا يمنع تقديم شهادة صالحة لـ evil.com من أجل bank.com. - إصدار TLS — يتفاوض JVM افتراضيًا على أعلى إصدار مدعوم مشترك. Java 17 يدعم TLS 1.2 و1.3؛ أما TLS 1.0 و1.1 فمعطّلان. لا تُخفّض هذا الإعداد أبدًا في الإنتاج.
أشيع مشكلة TLS في البيئات الداخلية أو بيئات التطوير هي الشهادة الموقّعة ذاتيًا. الحل الصحيح هو إضافة تلك الشهادة إلى مخزن ثقة مخصّص — لا تعطيل التحقق.
trustAllCerts() أو ضبط TrustManager فارغ يُزيل كل ضمانات TLS. يمكن للمهاجم اعتراض الاتصال بأي شهادة. يظهر هذا أحيانًا في كود الاختبارات — احتفظ به صارمًا في الاختبارات فقط خلف علامة، ولا تضعه في أي مسار إنتاجي.
الصورة الكاملة
الكود الشبكي على مستوى الإنتاج يجمع المخاوف الأربع معًا في آنٍ واحد. النمط هو: HttpClient واحد مشترك مع مجمّع اتصالات ومهلة اتصال؛ وطلبات بمهلات فردية؛ ومساعد إعادة محاولة يُطبّق التراجع الأسّي للأخطاء المؤقتة فقط؛ وTLS مع التحقق السليم من الشهادات.
- مهلة الاتصال مضبوطة على مستوى العميل.
- مهلة الطلب مضبوطة لكل طلب.
- حلقة إعادة محاولة مع تراجع أسّي وعشوائية — للأخطاء المؤقتة والعمليات الآمنة للتكرار فقط.
HttpClientيُنشأ مرة واحدة ويُعاد استخدامه (أو يُؤخذ من حاوية حقن التبعيات).- التحقق من شهادات TLS مُفعَّل؛ تُضاف CA المخصّصة إلى مخزن الثقة ولا تُعطَّل.
- تسجيل منظّم لأعداد المحاولات ورموز الحالة والوقت المنقضي من أجل الرصد.
الخلاصة
اضبط دائمًا مهلة الاتصال ومهلة الطلب — فكلٌّ منهما يحمي من نمط فشل مختلف. استخدم التراجع الأسّي مع العشوائية في إعادة المحاولة، وأعِد المحاولة للأخطاء الآمنة للتكرار والمؤقتة فقط. أعِد استخدام نسخة HttpClient واحدة للاستفادة من مجمّع اتصالاتها وتجنّب تكلفة مصافحات TCP وTLS المتكررة. افهم سلسلة ثقة TLS والتحقق من اسم المضيف التي يُطبّقها Java افتراضيًا؛ وأضِف CA المخصّصة إلى مخزن الثقة بدلًا من تعطيل التحقق. هذه الممارسات تجعل كود الشبكات لديك مرنًا وفعّالًا وآمنًا.