Conditional GET — آلية HTTP تسمح للعميل بالتحقق من حداثة المورد المخزن مؤقتًا قبل التحميل الكامل. يرسل العميل طلب GET مع رؤوس If-None-Match (التي تحتوي على ETag) أو If-Modified-Since (التي تحتوي على تاريخ)، ويعيد الخادم 304 Not Modified بدون نص استجابة إذا لم يتغير المورد. وفقًا لـ MDN Web Docs, 2025، تعمل الطلبات الشرطية على تقليل حركة مرور الشبكة للخوادم والعملاء. 304 Not Modified هي حالة HTTP رئيسية للمزامنة الفعالة للتطبيقات المحمولة.
أهم النقاط
Conditional GET هو طلب GET يحتوي على رأس شرطي واحد أو أكثر، بناءً عليها يقرر الخادم ما إذا كان سيعيد استجابة كاملة أم مجرد الحالة 304 Not Modified. الهدف الرئيسي هو تجنب نقل نص الاستجابة إذا لم يتغير المورد منذ آخر طلب. هذه آلية تخزين مؤقت أساسية في HTTP محددة في RFC 7232.
للتطبيقات المحمولة، يعد Conditional GET من أكثر الطرق فعالية لتحسين حركة مرور الشبكة. سيناريو نموذجي: عند فتح التطبيق، يرسل العميل سلسلة من طلبات GET الشرطية لتحميل الخلاصة والملف الشخصي والإعدادات. إذا لم تتغير البيانات، يتلقى التطبيق 304 ويستخدم النسخة المحلية. يستغرق هذا ميلي ثانية بدلاً من ثوانٍ ولا يستهلك بيانات الجوال.
وفقًا لـ Google Web Fundamentals (2025)، فإن تنفيذ طلبات GET الشرطية في تطبيق محمول يقلل متوسط وقت التحميل بنسبة 40–60% للزيارات المتكررة ويخفض استخدام حركة المرور بنسبة 70–90% للصفحات ذات التحديثات النادرة. يكون التأثير ملحوظًا بشكل خاص على الاتصالات البطيئة (3G، Edge)، حيث كل بايت مهم.
تتكون العملية من ثلاث خطوات. الأولى — يرسل العميل طلب GET عادي، ويعيد الخادم المورد مع رؤوس التخزين المؤقت (ETag، Last-Modified). الثانية — يحفظ العميل المورد ومدققاته محليًا. الثالثة — عند طلب متكرر، يرسل العميل GET مع If-None-Match (لـ ETag) و/أو If-Modified-Since (لـ Last-Modified). يتحقق الخادم من المدققات ويستجيب بـ 304 إذا لم يتغير المورد، أو 200 مع بيانات جديدة.
يستخدم الخادم أولوية ETag على Last-Modified عند وجود كلا الرأسين. وذلك لأن ETag يوفر تحققًا أكثر دقة — يتغير تجزئة المحتوى مع أي تعديل، بينما Last-Modified لديه دقة ثانية واحدة. إذا تطابق ETag، يعيد الخادم فورًا 304 دون التحقق من Last-Modified.
مثال على دورة كاملة لـ Conditional GET في تسلسل الطلبات:
// الخطوة 1: الطلب الأول — الحصول على البيانات و ETag
GET /api/profile
Response: 200 OK
ETag: "33a64df551425fcc55e"
Body: { "name": "Alice" }
// الخطوة 2: تكرار الطلب — مع If-None-Match
GET /api/profile
If-None-Match: "33a64df551425fcc55e"
Response: 304 Not Modified
// نص الاستجابة غائب — استخدام النسخة المحلية
في الطلب الثاني، يقارن الخادم ETag من If-None-Match مع تجزئة المورد الحالية. إذا تطابقت، يعيد 304 بدون نص — يواصل العميل استخدام البيانات المخزنة مؤقتًا. هذا هو جوهر Conditional GET: الحد الأدنى من حركة المرور مع أقصى حداثة للبيانات.
طلب GET العادي يعيد دائمًا استجابة كاملة 200 OK مع نص. حتى إذا لم يتغير المورد، ينقل الخادم جميع البيانات مرة أخرى. هذا مقبول للموارد الصغيرة أو الطلبات النادرة، ولكن للتطبيقات المحمولة مع مئات الطلبات عند كل تشغيل، يؤدي هذا النهج إلى استهلاك مفرط لحركة المرور والبطارية.
Conditional GET يضيف حملًا إضافيًا في شكل رؤوس (عادةً 50–200 بايت لكل طلب) لكنه يوفر الكيلوبايتات والميغابايتات مع استجابة 304. كلما كان المورد أكبر، كانت الفائدة أكبر. للصور وقوائم البيانات ومستندات JSON من 10 كيلوبايت فما فوق، يؤتي Conditional GET ثماره من أول طلب متكرر.
خصائص مقارنة للنهجين:
| المعامل | GET العادي | Conditional GET |
|---|---|---|
| حركة المرور (بدون تغييرات) | استجابة كاملة | رؤوس فقط (~200 بايت) |
| زمن الاستجابة | تحميل كامل | ميلي ثانية (304) |
| حمل الخادم | توليد + نقل | فحص ETag فقط |
| تعقيد التنفيذ | أدنى | يتطلب تخزين ETag |
| الكفاءة للبيانات الكبيرة | منخفضة | عالية |
دعونا نلقي نظرة على تنفيذ كامل لـ Conditional GET في Kotlin باستخدام OkHttp و Room لتخزين ETag. تطبيق قائمة المهام يقوم بتحميل المهام من الخادم ويستخدم الطلبات الشرطية لتقليل حركة المرور. يتم تخزين ETags في قاعدة بيانات محلية للاستمرار بين الجلسات.
مستودع مع Conditional GET في Kotlin:
class TaskRepository(
private val api: TaskApi,
private val etagDao: EtagDao
) {
suspend fun getTasks(): List<Task> {
val savedEtag = etagDao.getEtag("tasks")
val response = api.fetchTasks(
ifNoneMatch = savedEtag
)
return when (response.code()) {
304 -> taskDao.getAll() // من ذاكرة التخزين المؤقت المحلية
200 -> {
response.header("ETag")?.let {
etagDao.saveEtag("tasks", it)
}
val tasks = response.body() ?: emptyList()
taskDao.replaceAll(tasks)
tasks
}
else -> throw Exception(
"Sync failed: ${response.code()}")
}
}
}
TaskRepository يتحقق من رمز الاستجابة: 304 يعني عدم وجود تغييرات، ويتم إرجاع البيانات من ذاكرة التخزين المؤقت المحلية لـ Room. عند 200، يتم حفظ ETag جديد وتحديث المهام في قاعدة البيانات المحلية. هذا النمط هو معيار للتطبيقات المحمولة مع مزامنة REST API.
يستخدم Conditional GET على نطاق واسع في التطبيقات المحمولة لتحسين مزامنة البيانات. السيناريوهات الرئيسية: تحميل خلاصات الأخبار (Twitter، Instagram يستفسرون دوريًا عن API مع If-None-Match)، تحديث الملفات الشخصية للمستخدمين، تحميل قوائم الإشعارات ومزامنة المهام. في كل حالة، يمكن للتطبيق التحقق من حداثة البيانات دون إعادة تحميلها.
لـ التطبيقات غير المتصلة أولاً، يعمل Conditional GET كالمرحلة الأولى من المزامنة. يرسل التطبيق أولاً طلبات GET شرطية لجميع الموارد التي تم تعديلها محليًا منذ آخر مزامنة. الموارد ذات 304 لا تتطلب تحميلًا. بعد ذلك، يرسل التطبيق PUT/POST للتغييرات المحلية. يضمن هذا النهج ثنائي المراحل الحد الأدنى من استهلاك حركة المرور.
بالاشتراك مع حل النزاعات، يسمح Conditional GET باكتشاف النزاعات بكفاءة. إذا تلقى العميل 200 مع بيانات جديدة (تغير المورد) ولكن لديه تغييرات محلية غير مرسلة — يتم تسجيل نزاع. يمكن للعميل إما تطبيق LWW (يتم فقدان التغييرات المحلية) أو بدء استراتيجية دمج لدمج التغييرات المحلية والبعيدة. وفقًا لمدونة Meta Engineering (2025)، أدى تنفيذ Conditional GET في Messenger إلى تقليل متوسط حركة مرور المزامنة بنسبة 73%.
الأسئلة الشائعة
Conditional GET — طلب HTTP GET مع رؤوس شرطية (If-None-Match، If-Modified-Since). يعيد الخادم 304 Not Modified إذا لم يتغير المورد، أو 200 مع بيانات جديدة. هذه آلية تخزين مؤقت فعالة.
GET العادي يعيد دائمًا استجابة كاملة مع نص. Conditional GET يضيف رؤوس التحقق من الإصدار (ETag، تاريخ). إذا لم تتغير البيانات، يستجيب الخادم بـ 304 بدون نص، مما يوفر حركة المرور ووقت التحميل.
للتخزين المؤقت الفعال، احفظ ETag و Last-Modified من كل استجابة خادم في قاعدة بيانات محلية. في الطلب التالي، أرسلهما في رؤوس If-None-Match و If-Modified-Since. عند 304، استخدم البيانات من الذاكرة المؤقتة المحلية.
في استجابة 304، لا ينقل الخادم نص الاستجابة — فقط الرؤوس (~200 بايت). لمورد بحجم 50 كيلوبايت، هذا يعني توفير 99.6% من حركة المرور. لتطبيق يتم مزامنته 50 مرة في اليوم، يصل التوفير إلى عشرات الميغابايتات شهريًا.
نعم، هذا هو النهج القياسي للمزامنة التفاضلية. يتحقق العميل من حداثة كل مورد عبر Conditional GET، ويحمل فقط الموارد التي تغيرت، ويرسل التغييرات المحلية. يستخدم هذا النهج في Twitter و Instagram و Telegram ومعظم واجهات API الحديثة.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.