ETag هو رأس استجابة HTTP يحتوي على معرّف فريد لإصدار المورد. يُنشئ الخادم ETag كقيمة تجزئة للمحتوى أو رقم إصدار ويعيده إلى العميل مع البيانات. في الطلبات اللاحقة، يرسل العميل هذا المعرّف في رأس If-None-Match، مما يسمح للخادم بالتحقق مما إذا كان المورد قد تغير. وفقًا لـ MDN Web Docs، 2025، فإن ETag هو أساس آلية طلبات GET الشرطية في HTTP. الطلبات الشرطية مع ETag تقلل حجم البيانات المنقولة أثناء مزامنة تطبيقات الجوال بنسبة تصل إلى 90%.
النقاط الرئيسية
ETag (Entity Tag) هو رأس HTTP من عائلة الرؤوس الشرطية الذي يتحقق من صحة الموارد المخزنة مؤقتًا. يحسب الخادم ETag كقيمة تجزئة (MD5، SHA-256) أو رقم إصدار المورد ويعيده استجابة لطلب GET. يخزن العميل ETag مع البيانات ويرسله في رأس If-None-Match في الطلبات اللاحقة. إذا لم يتغير محتوى المورد، يستجيب الخادم بحالة 304 Not Modified بدون نص استجابة.
لتطبيقات الجوال، ETag مهم جدًا لأنه يقلل كمية البيانات التي يتم تنزيلها. عند كل تشغيل أو مزامنة، يتحقق التطبيق من حداثة الموارد بطلب If-None-Match — بدلاً من تحميل البيانات كاملة، يتلقى 304 ويستخدم النسخة المحلية. وفقًا لفريق Google Chrome (2024)، فإن استخدام ETag في واجهات برمجة التطبيقات للجوال يقلل متوسط حجم الاستجابة بنسبة 87% للقوائم و94% للكائنات الفردية.
يتم إنشاء ETag من جانب الخادم ويمكن أن يكون حتميًا (متطابقًا للمحتوى المتطابق، مفيدًا للتخزين المؤقت المشترك) أو فريدًا لكل استجابة (للتحقق الصارم). في REST API المصممة لمزامنة الجوال، التركيبة الأكثر شيوعًا هي تجزئة المحتوى ورقم إصدار السجل في قاعدة البيانات.
ETags القوية (strong ETag) هي معرفات تتغير مع أي تعديل في المحتوى، بما في ذلك التغييرات الطفيفة (المسافات، التنسيق). التنسيق: «abc123def» (بين علامتي اقتباس مزدوجتين، بدون بادئة). تضمن ETags القوية أن المورد لم يتغير بايت ببايت. وهي إلزامية لطلبات النطاق (Range requests) وللتحقق من سلامة التنزيلات الجزئية.
ETags الضعيفة (weak ETag) هي معرفات ببادئة W/، على سبيل المثال W/«abc123def». تسمح بأن يكون المورد مكافئًا دلاليًا حتى لو اختلف التمثيل البايتي. ETags الضعيفة مفيدة للخوادم التي تنشئ استجابات ديناميكيًا بمسافات أو تنسيق مختلف ولكن بنفس المعنى. ومع ذلك، لا تدعم ETags الضعيفة طلبات النطاق.
مقارنة أنواع ETag:
| الخاصية | ETag قوي | ETag ضعيف |
|---|---|---|
| التنسيق | «hash» | W/«hash» |
| الحساسية | بايت ببايت | دلالية |
| طلبات Range | مدعومة | غير مدعومة |
| تخزين CDN المؤقت | مثالي | محدود |
| المزامنة | دقة عالية | يسمح بالتصادم |
Last-Modified هو رأس HTTP يشير إلى تاريخ ووقت آخر تعديل للمورد. يعيد العميل إرساله في رأس If-Modified-Since. Last-Modified أبسط في التنفيذ (الخادم يحتاج فقط إلى تاريخ)، لكن له قيود أساسية: دقة ثانية واحدة (تعديلان في نفس الثانية لا يمكن تمييزهما) وعدم القدرة على تحديد ما إذا كان المحتوى قد تغير إذا كان الطابع الزمني هو نفسه (على سبيل المثال، بعد استعادة نسخة احتياطية).
ETag يحل هذه المشكلات: تتغير تجزئة المحتوى مع أي تعديل بغض النظر عن الوقت. لذلك، تستخدم REST API الحديثة مزيجًا من كلا الرأسين: ETag للتحقق الدقيق وLast-Modified للتصفية التقريبية في CDN. يُنشئ Apache HTTP Server وNginx كلا الرأسين للملفات الثابتة افتراضيًا.
لتطبيقات الجوال مع المزامنة، ETag أكثر أهمية لأنه يسمح باكتشاف تضاربات التحرير. إذا أرسل العميل طلب PUT مع If-Match: «etag»، يرفض الخادم الطلب إذا تم تعديل المورد بواسطة عميل آخر (القفل التفاؤلي). لا يمكن لـ Last-Modified ضمان هذه الموثوقية بسبب دقة الثانية.
لنلقِ نظرة على تنفيذ من جانب العميل لـ ETag في تطبيق جوال باستخدام Kotlin مع Retrofit وOkHttp. في كل طلب GET، يحفظ العميل ETag من الاستجابة، وفي الطلب التالي يرسله في رأس If-None-Match. إذا أعاد الخادم 304، لا يتم تنزيل البيانات مرة أخرى.
إعداد عميل OkHttp مع التخزين المؤقت لـ ETag:
class EtagClient {
private val etagCache =
mutableMapOf<String, String>()
private val client = OkHttpClient.Builder().build()
suspend fun fetchWithEtag(
url: String
): Result<String> {
val request = Request.Builder()
.url(url)
.header("If-None-Match",
etagCache[url] ?: "")
.build()
val response = client.newCall(request).await()
return when (response.code) {
304 -> Result.success(
"not_modified")
200 -> {
response.header("ETag")?.let {
etagCache[url] = it
}
Result.success(response.body?.string()
?: "")
}
else -> Result.failure(
Exception("HTTP ${response.code}"))
}
}
}
يحفظ العميل ETag بعد استجابة 200 ناجحة ويرسله في رأس If-None-Match في الطلب التالي. عند استجابة 304، يعرف العميل أن النسخة المحلية حديثة ولا يهدر البيانات في إعادة التنزيل. يقلل هذا النمط تكاليف شبكة تطبيق الجوال بنسبة 80–90% للموارد المطلوبة بشكل متكرر.
ETag هو آلية رئيسية لتحسين مزامنة تطبيقات الجوال مع REST API. في مخطط المزامنة القياسي، يطلب العميل أولاً قائمة الموارد مع التحقق من ETag — إذا لم يتغير أي مورد، يعيد الخادم 304 ويكمل العميل المزامنة. إذا كانت هناك تغييرات، يعيد الخادم الموارد المعدلة فقط. يُسمى هذا النهج المزامنة التفاضلية وهو مهم جدًا للأجهزة المحمولة ذات البيانات المحدودة.
في سيناريوهات القفل التفاؤلي، يُستخدم ETag لمنع تضاربات Lost Update. عندما يرسل العميل طلب PUT لتحديث مورد، يتضمن رأس If-Match: «etag». إذا لم يتطابق ETag (قام عميل آخر بالفعل بتعديل المورد)، يستجيب الخادم بـ 412 Precondition Failed، ويجب على العميل إعادة تحميل الإصدار الحالي وإعادة محاولة التعديل. يضمن هذا النهج اتساق البيانات بدون أقفال على مستوى قاعدة البيانات.
للأنظمة الموزعة مع وضع عدم الاتصال، يُستخدم ETag بدمج مع حل التضارب. يقوم العميل بالمزامنة عن طريق الحصول على ETags الحالية لجميع الموارد. عند إرسال التغييرات، يتحقق الخادم من If-Match — إذا لم يتطابق ETag، يتم تسجيل تضارب يتم حله وفقًا للاستراتيجية المختارة (LWW، Merge). وفقًا لتقرير Postman API (2025)، 67% من REST API الإنتاجية لتطبيقات الجوال تستخدم ETag كآلية رئيسية للتحقق من الإصدارات.
الأسئلة الشائعة
ETag هو رأس استجابة HTTP يحتوي على معرّف فريد لإصدار المورد. يستخدمه العميل للطلبات الشرطية: إذا لم يتغير المورد، يعيد الخادم 304 Not Modified بدون نص استجابة، مما يوفر البيانات.
ETag يستخدم تجزئة المحتوى للمقارنة الدقيقة. Last-Modified يعتمد على تاريخ التعديل بدقة ثانية. ETag أكثر موثوقية لاكتشاف التغييرات الفعلية ويدعم القفل التفاؤلي عبر If-Match.
ETags القوية (بدون بادئة) تميز الموارد بايت ببايت. ETags الضعيفة (ببادئة W/) تسمح بالتكافؤ الدلالي. القوية مطلوبة لطلبات النطاق، والضعيفة للمحتوى المُنشأ ديناميكيًا.
ETag يقلل البيانات بنسبة 80–90%: يتحقق العميل من حداثة جميع الموارد عبر If-None-Match، ويقوم بتنزيل الموارد المتغيرة فقط. بدون ETag، كان العميل سينزل بيانات كاملة في كل مزامنة، مما يهدر البيانات والبطارية.
يحسب الخادم ETag كتجزئة (MD5، SHA-256) لمحتوى الاستجابة أو يستخدم رقم إصدار السجل من قاعدة البيانات. في Spring Boot، التعليق @Cacheable مع etag = true كافٍ. في Express.js، الوسيط etag مفعل افتراضيًا.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.