ETag (Entity Tag) — هدر HTTP است که یک شناساگر منحصربهفرد از نسخه منبع را در سرور تعیین میکند و به مشتری امکان بررسی مؤثر استحقاق دادههای ذخیرهشده را میدهد. در درخواست مجدد، مرورگر یا برنامه ETag ذخیرهشده را ارسال میکند و سرور آن را با مقدار فعلی مقایسه میکند: در صورت تطابق، وضعیت 304 Not Modified بدون بدنه پاسخ برگردانده میشود. به استناد به RFC 7232 (IETF, 2014)، درخواستهای شرطی با ETag حجم دادههای انتقالی را تا 95% برای منابع مکرر کاهش میدهند. این هدر را برای عملکرد برنامههای موبایل حیاتی تهیه میکند.
نکات کلیدی
ETag (Entity Tag) — هدر پاسخ HTTP است که شامل یک شناساگر منحصربهفرد از نسخه مشخص منبع است. سرور ETag را بر اساس محتوای فایل، فرادادههای آن یا شماره بازنگری محاسبه میکند و آن را در پاسخ به درخواست GET به مشتری ارسال میکند. مشتری این شناساگر را ذخیره میکند و در درخواستهای بعدی به همان منبع، آن را در هدر If-None-Match ارسال میکند. اگر منبع تغییر نکرده باشد، سرور پاسخ 304 Not Modified را برمیگرداند و مشتری از نسخه ذخیرهشده خود استفاده میکند.
فرمت ETag در RFC 7232 به عنوان یک رشته در گیومه تعریف شده است: "33a64df551425fcc55e4d42a148795d9f25f89d4". مقدار میتواند هش SHA-1 محتوای فایل، شماره نسخه افزایشی، ترکیبی از inode-شماره-زمان برای فایلهای استاتیک یا یک توکن دلخواه تولیدشده توسط سرور باشد. تنها شرط این است که مقدار باید با هر تغییر منبع تغییر کند و اگر منبع ثابت باقی بماند، تغییر نکند.
ETag متعلق به مکانیزمهای درخواستهای شرطی (conditional requests) است — یکی از بهینهسازیهای پایه پروتکل HTTP. بر خلاف درخواستهای بدون شرط که سرور همیشه پاسخ کامل را برمیگرداند، درخواست شرطی به مشتری امکان بررسی اعتبار حافظه پنهان را بدون دوباره دانلود دادهها میدهد. به استناد به دادههای HTTP Archive (2025)، حدود 40% از کلیه پاسخهای HTTP به دلیل پیکربندی مناسب ETag و Last-Modified، 304 Not Modified هستند.
ETag در REST API برای بهینهسازی بارگیری کلکشیونهای داده استفاده میشود — اگر لیست اشیا تغییر نکرده باشد، مشتری 304 را بدون ارسال کل JSON دریافت میکند. در فایلهای استاتیک (CSS, JS, تصاویر) ETag به CDN و مرورگرها امکان بررسی مؤثر اعتبار حافظه پنهان را میدهد. در برنامههای موبایل، ETag برای همگامسازی پسزمینه حیاتی است: برنامه بررسی میکند که آیا دادهها در سرور تغییر کردهاند و بهروزرسانیها را فقط در ضرورت دانلود میکند. این به صرفهجویی در پنهای باند و باتری دستگاه کمک میکند.
چرخه کامل کار ETag از چهار مرحله تشکیل شده است. سرور در درخواست اول ETag را تولید و آن را در هدر پاسخ برمیگرداند. مشتری ETag را همراه منبع ذخیرهشده ذخیره میکند. در درخواست مجدد، مشتری هدر If-None-Match را با مقدار ETag ذخیرهشده ارسال میکند. سرور مقدار دریافتی را با ETag فعلی منبع مقایسه میکند: در صورت تطابق، 304 Not Modified با بدنه خالی و در صورت غیره، 200 OK با منبع جدید و ETag جدید برمیگرداند.
// درخواست مشتری با If-None-Match
GET /api/users HTTP/1.1
Host: example.com
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
// پاسخ سرور — منبع تغییر نکرده است
HTTP/1.1 304 Not Modified
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
در یک برنامه موبایل، این چرخه میتواند از طریق یک مشتری HTTP با پشتیبانی از ذخیرهسازی پیادهسازی شود. OkHttp، به عنوان مثال، به طور خودکار ETag را از طریق CacheInterceptor مدیریت میکند: ETag پاسخ را ذخیره و در درخواست مجدد If-None-Match را اضافه میکند. پس از دریافت 304، OkHttp دادههای ذخیرهشده را برمیگرداند. OkHttp بدون پیکربندی اضافی از ETag پشتیبانی میکند — کافی است حافظه پنهان را از طریق OkHttpClient.Builder.cache() فعال کنید.
سرور میتواند ETag را به روشهای مختلف محاسبه کند: از طریق هش MD5 یا SHA محتوا، از طریق شماره بازنگری از پایگاه داده (مثلاً updated_at از MySQL)، از طریق ترکیب inode + mtime + size برای فایلهای استاتیک (Nginx ETag را دقیقاً به این روش تولید میکند). برای APIهای دینامیک، مقاومترین روش هش محتوا است: اگر پاسخ JSON حتی یک فیلد را تغییر دهد، ETag تغییر خواهد کرد. اما محاسبه هش در هر درخواست پردازنده را مشغول میکند — برای سیستمهای با بار بالا بهتر است از شماره نسخه افزایشی استفاده کنید.
RFC 7232 دو نوع ETag تعریف میکند: قوی (strong) و ضعیف (weak). ETag قوی به این معنی است که دو نمایش از منبع بایت-به-بایت یکسان هستند — هیچ بیتی تفاوت ندارد. ETag ضعیف (پیشوند W/) فقط معادلت معنایی را تضمین میکند: محتوا میتواند در سطح سریالیسازی تفاوت داشته باشد (فاصلهها، ترتیب فیلدهای JSON)، اما دادهها برای مشتری یکسان در نظر گرفته میشوند. ETagهای ضعیف با پیشوند W/ علامتگذاری میشوند، مثلاً W/"1a2b3c".
انتخاب نوع ETag به نیازهای دقت مقایسه بستگی دارد. برای فایلهای استاتیک (CSS, JS, تصاویر) ETag قوی ترجیح دارد — اگر فایل تغییر کرده باشد، مشتری باید نسخه جدید را دریافت کند. برای APIهای دینامیک که همان JSON میتواند با ترتیب مختلف فیلدها یا فرمتبندی سریالیسازی شود، ETagهای ضعیف انعطاف بیشتری میدهند: سرور ETag را بر اساس دادههای کسب و کار تولید میکند، نه نمایش رشتهای.
| نوع ETag | فرمت | تضمین | کاربرد |
|---|---|---|---|
| Strong (قوی) | "هش" | یکسانی بایت-به-بایت | فایلهای استاتیک، منابع دودویی |
| Weak (ضعیف) | W/"هش" | معادلت معنایی | JSON API، صفحات دینامیک |
محدودیت ETagهای ضعیف: آنها نمیتوانند با درخواستهای محدوده (Range requests) استفاده شوند. اگر مشتری بخشی از فایل را درخواست کند، سرور باید یک ETag قوی برگرداند تا تضمین کند که قسمت مربوط به منبع کامل است. ETagهای ضعیف چنین تضمینی را ارائه نمیدهند. در سایر سناریوها، ETagهای ضعیف ایمن هستند و برای API توصیه میشوند.
ETag و Last-Modified دو هدر HTTP برای درخواستهای شرطی هستند که اغلب با هم استفاده میشوند. Last-Modified تاریخ آخرین تغییر منبع را نشان میدهد و با هدر If-Modified-Since کار میکند. ETag یک شناساگر منحصربهفرد نسخه را ارائه میدهد و با If-None-Match کار میکند. هر کدام مزایا و محدودیتهای خود را دارند و ترکیب آنها حداکثر بهایی ذخیرهسازی را فراهم میکند.
Last-Modified در پیادهسازی سادهتر است — سرور به طور خودکار تاریخ را از سیستم فایل دریافت یا فیلد updated_at را در پایگاه داده بهروز میکند. اما دقت تاریخ تا حد ثانیه است که برای منابعی که چندین بار در ثانیه تغییر میکنند کافی نیست. علاوه بر این، Last-Modified وضعیتهای مختلف را تمایز نمیدهد: اگر فایل با همان نسخه بازنویسی شود، تاریخ تغییر میکند اما محتوا نمیکند — مشتری دادههای یکسان را دوباره دانلود میکند.
ETag دقیقتر است: فقط در صورت تغییر واقعی محتوا تغییر میکند. اگر سرور نسخه قبلی را از پشتیبان بازگرداند، ETag تغییر خواهد کرد. اگر فایل با همان دادهها بازنویسی شود — ETag ثابت میماند و مشتری دوباره دانلود نمیکند. استفاده مشترک توسط مشخصات HTTP توصیه شده است: سرور هر دو هدر را برمیگرداند، مشتری If-None-Match و If-Modified-Since را همزمان ارسال میکند. اگر حتی یک هدر تغییر را نشان دهد — سرور منبع جدید را برمیگرداند.
بر اساس مشخصات، ETag بر Last-Modified اولویت دارد. اگر سرور If-None-Match را دریافت کرده باشد، باید فقط ETag را بررسی کند و If-Modified-Since را نادیده بگیرد. این از race condition جلوگیری میکند: اگر منبع بین ارسال Last-Modified توسط مشتری و بررسی در سرور تغییر کرده باشد، ETag نشانگر جدیدتری خواهد بود. در عمل، سرورها معمولاً هر دو هدر را بررسی میکنند، اما در صورت ناهماهنگی نتایج ETag پیروز میشود.
پیکربندی ETag به نوع سرور بستگی دارد. Nginx ETag را برای فایلهای استاتیک به طور خودکار بر اساس inode، mtime و اندازه تولید میکند. Apache از مکانیزم FileETag استفاده میکند. برای برنامههای دینامیک در Node.js، PHP، Python، Ruby ETag باید به طور برنامهای تولید شود — از طریق هش پاسخ، شماره نسخه دادهها یا ترکیب پارامترهای درخواست.
func etagMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter,
r *http.Request) {
// تولید ETag بر اساس دادهها
etag := generateETag(r.URL.Path)
w.Header().Set("ETag", etag)
// بررسی If-None-Match
if r.Header.Get("If-None-Match") == etag {
w.WriteHeader(http.StatusNotModified)
return
}
next.ServeHTTP(w, r)
})
}
میانافزار Go درخواست را گیرفتار میکند، ETag را برای URL درخواستشده تولید میکند (مثلاً هش دادهها را از حافظه پنهان یا پایگاه داده محاسبه میکند) و هدر پاسخ را تنظیم میکند. اگر مشتری If-None-Match ارسال کرده باشد و آن با ETag فعلی مطابقت داشته باشد، سرور بلافاصله 304 Not Modified را بدون فراخوانی هندلر اصلی برمیگرداند. در محیط تولید، برای کاهش بار سرور، ذخیرهسازی ETagهای محاسبهشده بر اساس URL و پارامترها اضافه شود.
در پیکربندی چند سروره (چرخشی round-robin یا anycast) ETag باید برای یک منبع مشخص در همه گرهها یکسان باشد. اگر ETag بر اساس inode فایل تولید شود و سایت روی چند سرور اجرا شود، مقادیر متفاوت خواهند بود. راه حل — استفاده از هش محتوا یا ذخیره متمرکز نسخه (Redis, etcd). مشکل دوم — فشردگی gzip: Nginx ETag را در صورت فعال بودن فشردگی تغییر میدهد که میتواند منجر به 304 های اضافی شود. برای همگامسازی ETag با محتوای فشرده، پیکربندی gzip_vary on مورد نیاز است.
سوالات متداول
بله، اگر سرور صریحاً از این جلوگیری نکرده باشد. ETag نیازی به تنها بودن سراسری ندارد — آن در چارچوب URL مشخص منحصربهفرد است. برای فایلهای استاتیک با استفاده از هش SHA، برخورد نادر است، اما برای تولید کنندههای دستی احتمال دوبلیکات وجود دارد.
ETag برای منابعی که مکرراً درخواست میشوند و به ندرت تغییر میکنند بیشترین بهایی را دارد: فایلهای استاتیک، لیستهای API، تنظیمات. برای صفحات منحصربهفردی که یک بار بارگیری میشوند (مثل صفحه تایید سفارش)، ETag مزیتی ندارد.
CDN ETag را در درخواستهای origin برای بررسی اعتبار حافظه پنهان در نظر میگیرد. اگر ETag منبع در origin تغییر کرده باشد، CDN نسخه جدید را دانلود میکند. Cloudflare و Fastly از ETag به عنوان یک مکانیزم استاندارد برای ابطال حافظه پنهان در سطح origin پشتیبانی میکنند.
RFC 7232 طول ETag را محدود نکرده است، اما سرورها و پروکسیها ممکن است مقادیر خیلی طولانی را قطع یا نادیده بگیرند. توصیه میشود از هشی با طول 20–40 کاراکتر یا ترکیبی از شناساگر نسخه و مجموع کنترلی استفاده کنید.
اینها مکانیزمهای جداگانه نیستند. Cache-Control سیاست ذخیرهسازی را تعیین میکند (چقدر ذخیره شود، به کوجا اجازه است)، و ETag مکانیزم اعتبارسنجی منبع ذخیرهشده است. پیکربندی بهینه شامل هر دو هدر به همراه است.
نتیجه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید