Last-Modified คือ header การตอบรับ HTTP ที่ระบุวันที่และเวลาของการแก้ไขล่าสุดของทรัพยากรบนเซิร์ฟเวอร์ ทําให้ไคลเอนต์สามารถทําคําขอแบบมีเงื่อนไขผ่าน If-Modified-Since ได้ หากทรัพยากรไม่มีการเปลี่ยนแปลงตั้งแต่วันที่ระบุ เซิร์ฟเวอร์จะส่งคืน 304 Not Modified โดยไม่ต้องส่งตัวเรื่องการตอบรับ ซึ่งช่วยประหยัดแบนด์วิดท์ได้อย่างมาก ตาม RFC 7232 (IETF, 2014) คําขอแบบมีเงื่อนไขกับ Last-Modified ช่วยลดเวลาโหลดหน้าได้ 30-60% เมื่อเยี่ยมชมซ้ํา header นี้ได้รับการสนับสนุนโดยอัตโนมัติจากเซิร์ฟเวอร์ HTTP และ proxy ส่วนใหญ่
ประเด็นสําคัญ
Last-Modified คือ HTTP header ที่อยู่ในกลุ่ม header คําขอแบบมีเงื่อนไข เซิร์ฟเวอร์เพิ่มลงในการตอบรับ GET หรือ HEAD โดยระบุวันที่และเวลาของการแก้ไขล่าสุดของทรัพยากรที่ร้องขอในรูปแบบ HTTP-date: Last-Modified: Wed, 02 Jul 2025 14:30:00 GMT ไคลเอนต์ (เบราว์เซอร์, แอปพลิเคชันมือถือ, proxy) เก็บวันที่นี้พร้อมกับทรัพยากรที่แคชไว้ เมื่อมีการร้องขอซ้ํา ไคลเอนต์จะส่ง header If-Modified-Since พร้อมวันที่เดียวกัน และเซิร์ฟเวอร์จะเปรียบเทียบกับเวลาแก้ไขปัจจุบันของทรัพยากร
โปรโตคอลคําขอแบบมีเงื่อนไขกับ Last-Modified ถูกกําหนดใน RFC 7232 และรองรับโดยเซิร์ฟเวอร์ HTTP ที่ทันสมัยทั้งหมด รูปแบบวันที่ถูกควบคุมอย่างเข้มงวด — เฉพาะ GMT (Greenwich Mean Time) โดยไม่มีการระบุเขตเวลา เซิร์ฟเวอร์ต้องส่งคืนวันที่ในสามรูปแบบที่เป็นไปได้: RFC 1123 (มาตรฐาน), RFC 850 (เก่า) หรือ ANSI C asctime ในทางปฏิบัติ เซิร์ฟเวอร์เกือบทั้งหมดใช้รูปแบบ RFC 1123 ที่มีความยาวคงที่ 29 ตัวอักษร
Last-Modified อยู่ในหมวดหมู่ของกลไกการตรวจสอบแคช: มันไม่ได้บอกไคลเอนต์ว่าการตอบรับ สามารถแคชได้หรือไม่ แต่ให้เครื่องมือสําหรับตรวจสอบความสดของทรัพยากรที่แคชไว้แล้ว นโยบายแคชถูกกําหนดแยกต่างหากผ่าน header Cache-Control จากการศึกษาของ Akamai (2025) การกําหนดค่า Last-Modified ที่ถูกต้องร่วมกับ Cache-Control ช่วยลดภาระบนเซิร์ฟเวอร์ต้นทางได้ถึง 70% สําหรับเนื้อหาคงที่
header Last-Modified ถูกกําหนดตั้งแต่ HTTP/1.0 (RFC 1945, 1996) และกลายเป็นหนึ่งในกลไกการจัดการแคชแรกๆ บนเว็บ ก่อนที่ ETag จะปรากฏใน HTTP/1.1 มันเป็นวิธีเดียวในการทําคําขอแบบมีเงื่อนไข แม้จะมีอายุมาก header นี้ยังคงมีความเกี่ยวข้องเนื่องจากความเรียบง่าย — เซิร์ฟเวอร์ไม่จําเป็นต้องคํานวณ hash ของเนื้อหา แค่ต้องอ่าน การประทับเวลาของไฟล์ จากระบบไฟล์หรือฟิลด์ updated_at จากฐานข้อมูล
วงจรสมบูรณ์ประกอบด้วยสามขั้นตอน ในการร้องขอครั้งแรก เซิร์ฟเวอร์ส่งคืนทรัพยากรพร้อม header Last-Modified และสถานะ HTTP 200 OK ไคลเอนต์แคชการตอบรับพร้อมวันที่ เมื่อมีการร้องขอซ้ํา ไคลเอนต์จะส่ง header 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 การประทับเวลาของ build artifact หากไม่ได้ตั้งค่า Last-Modified อย่างชัดเจน เซิร์ฟเวอร์อาจไม่ส่ง header เลย และไคลเอนต์จะไม่สามารถทํา คําขอแบบมีเงื่อนไข ตามวันที่ได้
Last-Modified และ ETag ทําหน้าที่คล้ายกัน — ให้ไคลเอนต์ตรวจสอบความสดของแคช — แต่มีความแตกต่างพื้นฐาน Last-Modified ใช้การประทับเวลา ETag ใช้ตัวระบุเวอร์ชันที่ไม่ซ้ํากัน แต่ละวิธีมีสถานการณ์ที่เหมาะสมกว่า และข้อกําหนด HTTP แนะนําให้ใช้ทั้งสอง header ร่วมกัน
| เกณฑ์ | Last-Modified | ETag |
|---|---|---|
| สาระสําคัญ | วันที่แก้ไขล่าสุด | ตัวระบุเวอร์ชันที่ไม่ซ้ํากัน |
| ความแม่นยํา | ถึงวินาที | ถึงบิต (hash) |
| ความซับซ้อนในการใช้งาน | ต่ํา — อัตโนมัติจากระบบไฟล์ | ปานกลาง — ต้องคํานวณ hash |
| เซิร์ฟเวอร์คลัสเตอร์ | ปัญหา: mtime อาจแตกต่างระหว่างโหนด | เสถียรกับข้อมูลเหมือนกันระหว่างโหนด |
| การรองรับช่วง | ไม่มีผลต่อการร้องขอ Range | ต้องการ ETag ที่แข็งแกร่งสําหรับช่วง |
| คําแนะนํา | สําหรับไฟล์คงที่และ API ง่ายๆ | สําหรับ API ที่ต้องการการตรวจสอบที่แม่นยํา |
ข้อได้เปรียบหลักของ Last-Modified คือความเรียบง่าย เซิร์ฟเวอร์ไม่จําเป็นต้องคํานวณ hash ของเนื้อหา ซึ่งช่วยประหยัด ทรัพยากร CPU ในแต่ละคําขอ สําหรับโปรเจ็กต์ที่มีปริมาณการเข้าชมสูงที่ให้บริการไฟล์คงที่หรือข้อมูลที่มีการประทับเวลาชัดเจน Last-Modified ยังคงเป็นตัวเลือกที่เหมาะสมที่สุด ในทางกลับกัน ETag ให้ความแม่นยําสัมบูรณ์ — การเปลี่ยนตัวอักษรหนึ่งตัวในการตอบรับ JSON จะเปลี่ยน ETag แต่อาจไม่เปลี่ยนวันที่ (หากไฟล์ถูกเขียนทับด้วยเวอร์ชันเดียวกัน)
ข้อกําหนดแนะนําให้ส่งคืนทั้งสอง header พร้อมกัน เซิร์ฟเวอร์รวมทั้ง Last-Modified และ ETag ในการตอบรับ 200 OK ไคลเอนต์ส่งทั้งสอง header แบบมีเงื่อนไข — If-Modified-Since และ If-None-Match เซิร์ฟเวอร์ตรวจสอบ ETag ก่อน (มีลําดับความสําคัญ) จากนั้น Last-Modified หากอย่างน้อยหนึ่ง แจ้งสัญญาณการเปลี่ยนแปลง — จะส่งคืนการตอบรับทั้งหมด ซึ่งให้ความยืดหยุ่นสูงสุด: ETag รับประกันความแม่นยํา Last-Modified ให้การตรวจสอบสํารองสําหรับไคลเอนต์ที่ไม่รองรับ ETag
การกําหนดค่า Last-Modified ขึ้นอยู่กับประเภทของเซิร์ฟเวอร์ สําหรับ Nginx และ Apache Last-Modified จะถูกตั้งค่าโดยอัตโนมัติสําหรับไฟล์คงที่โดยอิงจาก mtime สําหรับแอปพลิเคชันแบบไดนามิก ต้องตั้งค่า header ในโค้ดเซิร์ฟเวอร์ มาดูการกําหนดค่าบนแพลตฟอร์มยอดนิยมกัน
// 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 สําหรับคําขอ proxy ไปยัง backend Last-Modified จะถูกส่งผ่านจากการตอบรับ upstream โดยไม่เปลี่ยนแปลง สําคัญ: หาก backend ไม่ส่งคืน Last-Modified Nginx จะไม่เพิ่มให้โดยอัตโนมัติสําหรับการตอบรับแบบไดนามิก
Last-Modified มีข้อจํากัดที่ทราบหลายประการ หลักคือความแม่นยําระดับวินาที หากทรัพยากรเปลี่ยนแปลงสองครั้งภายในหนึ่งวินาที ไคลเอนต์อาจพลาดเวอร์ชันใหม่ ในทางปฏิบัตินี้เป็นสถานการณ์ที่หายาก แต่สําหรับการอัปเดตความถี่สูง (ฟีด ticker, แชท) แนะนําให้ใช้ ETag ข้อจํากัดที่สองคือ ปัญหาคลัสเตอร์: บนเซิร์ฟเวอร์ที่แตกต่างกัน ไฟล์อาจมี mtime ที่แตกต่างกันเนื่องจากการคัดลอกหรือปรับใช้ ทําให้ Last-Modified ไม่สอดคล้องกัน
ข้อจํากัดที่สาม — การจัดการ If-Modified-Since ด้วยความแม่นยําระดับวินาทีอาจนําไปสู่การร้องขอที่ไม่จําเป็นเมื่อสอบถามเซิร์ฟเวอร์บ่อยครั้ง หากไคลเอนต์ส่ง If-Modified-Since ทุก 500 ms เซิร์ฟเวอร์จะส่งคืน 200 OK ทุกครั้งเนื่องจากวันที่ไม่เปลี่ยนแปลง แต่ทรัพยากรถูกอัปเดตแล้ว วิธีแก้ไขคือใช้ การรวมกับ ETag: ETag จะตรวจจับการเปลี่ยนแปลงภายในหนึ่งวินาที ในขณะที่ Last-Modified ยังคงเป็นตัวสํารอง
ปัญหาที่สี่ — Last-Modified ไม่แยกความแตกต่างระหว่างเวอร์ชันต่างๆ ของทรัพยากรเดียวกันที่มีวันที่เดียวกัน หากไฟล์ถูกกู้คืนจากสํารองและ mtime ตรงกับต้นฉบับ ไคลเอนต์จะไม่สังเกตว่าเนื้อหาเปลี่ยนไป ETag แก้ปัญหานี้: hash ของเนื้อหา จะเปลี่ยนแปลงอย่างแน่นอนเมื่อมีการเปลี่ยนแปลงข้อมูลใดๆ โดยไม่ขึ้นกับการประทับเวลา สําหรับข้อมูลสําคัญ ให้ใช้ทั้งสอง header เสมอ
คําถามที่พบบ่อย
เฉพาะ 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 เพื่อตรวจสอบ ความสด
ตรวจสอบว่าเซิร์ฟเวอร์กําลังตั้งค่า header จากแหล่งที่ถูกต้อง — ฐานข้อมูล ระบบไฟล์ หรือ API สําหรับการตอบรับแบบไดนามิก ตรวจสอบให้แน่ใจว่าคุณเรียก res.setHeader("Last-Modified", ...) อย่างชัดเจนในโค้ดตัวจัดการ
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ