Last-Modified — یک هدر پاسخ HTTP است که تاریخ و زمان آخرین تغییر منبع را در سرور مشخص میکند، و به مشتری اجازه میدهد از طریق If-Modified-Since درخواستهای شرطی انجام دهد. اگر منبع از تاریخ مشخصشده تغییر نکرده باشد، سرور 304 Not Modified را بدون ارسال بدنه پاسخ برمیگرداند که بهطور قابلتوجهی در پنهای صرفهجویی میکند. به استناد به RFC 7232 (IETF, 2014)، درخواستهای شرطی با Last-Modified زمان بارگیری صفحات را در بازدیدهای مجدد 30—60% کاهش میدهند. این هدر توسط اکثر سرورهای HTTP و پروکسیها بهطور خودکار پشتیبانی میشود.
نکات کلیدی
Last-Modified — یک هدر HTTP است که به گروه هدرهای درخواستهای شرطی (conditional requests) تلق میشود. سرور آن را در پاسخ GET یا HEAD اضافه میکند و تاریخ و زمان آخرین تغییر منبع مورد درخواست را به فرمت HTTP-date مشخص میکند: Last-Modified: Wed, 02 Jul 2025 14:30:00 GMT. مشتری (مرورگر، برنامهٔ موبایل، پروکسی) این تاریخ را همراه با منبع ذخیرهشده نگه میدارد. در درخواست مجدد، مشتری هدر If-Modified-Since را با همان تاریخ ارسال میکند و سرور آن را با زمان فعلی تغییر منبع مقایسه میکند.
پروتکل درخواستهای شرطی با Last-Modified در RFC 7232 تعریف شده است و توسط همهٔ سرورهای HTTP مدرن پشتیبانی میشود. فرمت تاریخ بهطور سختگیرانه تعیین شده است — تنها GMT (Greenwich Mean Time) بدون مشخص کردن منطقه زمانی. سرور باید تاریخ را به یکی از سه فرمت ممکن بازگرداند: RFC 1123 (استاندارد)، RFC 850 (منسوخ) یا ANSI C asctime. در عمل، تقریباً همهٔ سرورها از فرمات RFC 1123 با طول ثابت 29 کاراکتر استفاده میکنند.
Last-Modified به دستهٔ مکانیسمهای اعتبارسنجی ذخیره تلق میشود: آن به مشتری نمیگوید که آیا میتوان پاسخ را ذخیره کرد، بلکه ابزاری برای بررسی اعتبار منبع از پیش ذخیرهشده فراهم میکند. سیاست ذخیرهسازی بهطور جداگانه از طریق هدر Cache-Control مشخص میشود. بر اساس تحقیقات Akamai (2025)، پیکربندی مناسب Last-Modified همراه با Cache-Control بار سرورهای اصلی را برای محتوای ساکن تا 70% کاهش میدهد.
هدر Last-Modified در HTTP/1.0 (RFC 1945, 1996) تعریف شد و یکی از اولین مکانیسمهای مدیریت ذخیره در وب بود. تا ظهور ETag در HTTP/1.1، این تنها راه انجام درخواستهای شرطی بود. با وجود سن، این هدر به دلیل سادگیاش همچنان مورداستفاده است — سرور نیازی به محاسبه هش محتوا ندارد، کافیست تایمستمپ فایل را از سیستم فایل یا فیلد updated_at را از پایگاه داده بخواند.
چرخهٔ کامل شامل سه مرحله است. در اولین درخواست، سرور منبع را با هدر Last-Modified و وضعیت HTTP 200 OK بازمیگرداند. مشتری پاسخ را همراه با تاریخ ذخیره میکند. در درخواست مجدد، مشتری هدر If-Modified-Since را با تاریخ ذخیرهشده ارسال میکند. سرور این تاریخ را با زمان فعلی تغییر منبع مقایسه میکند. اگر منبع تغییر نکرده باشد — 304 Not Modified با بدنهٔ خالی بازگردانده میشود. اگر تغییر کرده باشد — 200 OK با دادههای جدید و Last-Modified جدید.
// درخواست اول — سرور منبع را با تاریخ بازمیگرداند
HTTP/1.1 200 OK
Content-Type: application/json
Last-Modified: Wed, 02 Jul 2025 14:30:00 GMT
[{"id": 1, "name": "Alice"}]
// درخواست مجدد — مشتری تاریخ ذخیرهشده را ارسال میکند
GET /api/users HTTP/1.1
Host: example.com
If-Modified-Since: Wed, 02 Jul 2025 14:30:00 GMT
// پاسخ — دادهها تغییر نکردهاند
HTTP/1.1 304 Not Modified
برای برنامههای موبایل، Last-Modified خصوصاً در هنگام همگامسازی داده مفید است. برنامه تاریخ آخرین بهروزرسانی موفق را ذخیره میکند و آن را در If-Modified-Since به سرور ارسال میکند. اگر دادهها بیشتر شده یا تغییر کرده باشند — سرور مجموعهٔ کامل را بازمیگرداند. در غیر این صورت — 304، و برنامه از نسخهٔ محلی استفاده میکند. OkHttp و URLSession این مکانیسم را از طریق سیستمهای ذخیره سازی داخلی خود بهطور خودکار پشتیبانی میکنند.
برای فایلهای ساکن، Nginx و Apache تاریخ را از ویژگیهای سیستم فایل — mtime (زمان تغییر) دریافت میکنند. برای محتوای دینامیک، کد سرور باید Last-Modified را بر اساس منطق کسبوکار بهطور صریح تعیین کند: فیلد updated_at از پایگاه داده، تاریخ آخرین commit در Git، تایمستمپ ساخت آرتفاکت. اگر Last-Modified بهطور صریح تعیین نشده باشد، سرور اصلاً هدر را بازنمیگرداند و مشتری نمیتواند بر اساس تاریخ درخواستهای شرطی انجام دهد.
Last-Modified و ETag وظیفهٔ مشابهی دارند — به مشتری امکان بررسی اعتبار ذخیره را میدهند — اما تفاوتهای اساسی دارند. Last-Modified از نشانگر زمان استفاده میکند، ETag از یک شناسهٔ یکتا نسخه. هر رویکرد سناریوهای خاصی دارد که در آنها کارامدتر است، و توصیهٔ مشخصات HTTP استفاده از هر دو هدر به صورت مشترک است.
| معیار | Last-Modified | ETag |
|---|---|---|
| ماهیت | تاریخ آخرین تغییر | شناسهٔ یکتا نسخه |
| دقت | تا ثانیه | تا بیت (هش) |
| پیچیدگی پیادهسازی | پایین — خودکار از سیستم فایل | متوسط — نیاز به محاسبهٔ هش |
| سرورهای خوشهای | مشکل: mtime میتواند در گرهها متفاوت باشد | پایدار در صورت دادههای یکسان در گرهها |
| پشتیبانی از محدوده | تأثیری بر Range requests ندارد | نیاز به ETag قوی برای محدودهها |
| توصیه | برای محتوای ساکن و APIهای ساده | برای APIهایی که بررسی دقیق مهم است |
مزیت اصلی Last-Modified سادگی است. سرور نیازی به محاسبه هش محتوا ندارد که در منابع CPU در هر درخواست صرفهجویی میکند. برای پروژههای با بار سنگین که فایلهای ساکن یا دادههای با نشانگر زمانی مشخص تحویل میدهند، Last-Modified گزینهٔ بهینه باقی میماند. ETag اما دقت مطلق را فراهم میکند — تغییر یک حرف در پاسخ JSON منجر به تغییر ETag میشود، اما ممکن است تاریخ را تغییر ندهد (اگر فایل با همان نسخه بازنویسی شده باشد).
مشخصات توصیه میکند هر دو هدر به صورت همزمان بازگردانده شوند. سرور هم Last-Modified و هم ETag را در پاسخ 200 OK قرار میدهد. مشتری هر دو هدر شرطی را — If-Modified-Since و If-None-Match ارسال میکند. سرور ابتدا ETag (اولویت دارد) و سپس Last-Modified را بررسی میکند. اگر حداقل یکی تغییر را نشان دهد — پاسخ کامل بازگردانده میشود. این حداکثر انعطافپذیری را فراهم میکند: ETag دقت را و Last-Modified بررسی پیشفرز را برای مشتریانی که ETag را پشتیبانی نمیکنند تامین میکند.
پیکربندی Last-Modified به نوع سرور بستگی دارد. برای Nginx و Apache، Last-Modified برای فایلهای ساکن بهطور خودکار بر اساس mtime ایجاد میشود. برای برنامههای دینامیک، هدر در کد سرور تنظیم میشود. بیایید تنظیمات را در پلتفرمهای محبوب بررسی کنیم.
// Express.js — تنظیم Last-Modified
app.get("/api/users", async (req, res) => {
const updatedAt = await getLastUpdate()
const ifModifiedSince = req.get("If-Modified-Since")
// بررسی If-Modified-Since
if (ifModifiedSince && new Date(ifModifiedSince)
>= updatedAt) {
return res.status(304).end()
}
const users = await getUsers()
res.set("Last-Modified", updatedAt.toUTCString())
res.json(users)
})
در مثال Express.js، سرور تاریخ آخرین بهروزرسانی داده را از پایگاه داده دریافت میکند، If-Modified-Since را از مشتری بررسی میکند و در صورت اعتبار ذخیره 304 را بازمیگرداند. اگر دادهها تغییر کرده باشد — Last-Modified جدید تعیین و پاسخ کامل بازگردانده میشود. toUTCString() تاریخ را به فرمات HTTP مورد نیاز تبدیل میکند. در محیط تولید، اضافه کردن ذخیره updatedAt در Redis برای جلوگیری از اجرای پرسان به پایگاه داده در هر درخواست ارزشمند است.
Nginx بهطور خودکار Last-Modified را برای فایلهای ساکن بر اساس زمان آخرین تغییر فایل تنظیم میکند. غیرفعال سازی یا تغییر رفتار از طریق دستور etag (غیرفعال سازی ETag) یا ماژول ngx_http_headers_module امکانپذیر است. برای درخواستهای پروکسی به backend، Last-Modified بدون تغییر از پاسخ upstream منتقل میشود. مهم: اگر backend Last-Modified را بازنگرداند، Nginx آن را برای پاسخهای دینامیک بهطور خودکار اضافه نمیکند.
Last-Modified چندین محدودیت شناخته شده دارد. اصلیترین دقت تا ثانیه است. اگر منبع دو بار در طول یک ثانیه تغییر کرده باشد، مشتری ممکن است نسخهٔ جدید را از دست بدهد. در عمل، این سناریو نادر است، اما برای بهروزرسانیهای با فرکانس بالا (فهرست نمودها، چتها) ETag توصیه میشود. محدودیت دوم مشکل خوشهای کردن است: در سرورهای مختلف، فایل ممکن است به دلیل کپی یا استقرار mtime متفاوتی داشته باشد، که منجر به ناهماهنگی Last-Modified میشود.
محدودیت سوم — پردازش If-Modified-Since با دقت تا ثانیه میتواند در پرسانهای مکرر به سرور منجر به درخواستهای ضائع شود. اگر مشتری هر 500 میلیثانیه If-Modified-Since ارسال کند، سرور هر بار 200 OK را بازمیگرداند، زیرا تاریخ تغییر نکرده، اما منبع در واقع بهروز شده است. راه حل استفادهٔ ترکیبی با ETag است: ETag تغییر در طول ثانیه را تشخیص میدهد و Last-Modified به عنوان پشتیبان باقی میماند.
چهارمین مشکل — Last-Modified نسخههای مختلف یک منبع با تاریخ یکسان را تفکیک نمیدهد. اگر فایل از پشتیبان بازگردانده شده باشد و mtime آن با اصلی مطابقت داشته باشد، مشتری متوجه تغییر محتوا نمیشود. ETag این مشکل را حل میکند: هش محتوا قاطعاً با هر تغییر دادهها، بدون توجه به نشانگر زمانی، تغییر میکند. برای دادههای حساس همیشه از هر دو هدر استفاده کنید.
سوالات متداول
تنها GMT (Greenwich Mean Time) در فرمات RFC 1123: روز هفته، تاریخ، ماه، سال، ساعت:دقیقه:ثانیه. مثال: Wed, 02 Jul 2025 14:30:00 GMT. منطقه زمانی همیشه GMT است، سایر فرماتها مجاز نیستند.
از نظر فنی بله، اما این RFC 7232 را نقض میکند. اگر سرور تاریخی در آینده را بازگرداند، مشتریان تا رسیدن آن تاریخ منبع را بهروز نمیکنند. چنین پیکربندی اشتباه محسوب میشود — تاریخ باید در گذشته یا حال باشد.
خیر، درخواستهای شرطی If-Modified-Since تنها با GET و HEAD کار میکنند. درخواستهای POST ذخیره نمیشوند و از اعتبارسنجی بر اساس تاریخ استفاده نمیکنند. برای بررسی اعتبار دادهها در POST از ETag یا مکانیسمهای سفارشی استفاده کنید.
Cache-Control سیاست ذخیرهسازی (حداکثر زمان نگهداری، کسانی که میتوانند ذخیره کنند) را مشخص میکند، و Last-Modified مکانیسم اعتبارسنجی ذخیرهٔ منسوخ است. پس از پایان max-age، مشتری If-Modified-Since را برای بررسی اعتبار ارسال میکند.
بررسی کنید که سرور هدر را از منبع اصلی — پایگاه داده، سیستم فایل یا API تنظیم میکند. برای پاسخهای دینامیک، مطمئن شوید که res.setHeader(«Last-Modified», ...) را در کد پردازشگر بهطور صریح فراخوانی میکنید.
نتیجهگیری
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید