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 ทั้งหมดคือ 304 Not Modified เนื่องจากการกำหนดค่า ETag และ Last-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 + ขนาดสำหรับไฟล์แบบคงที่ (Nginx สร้าง ETag ด้วยวิธีนี้) สำหรับ API แบบไดนามิก แฮชเนื้อหาเป็นวิธีที่น่าเชื่อถือที่สุด: หากการตอบสนอง JSON เปลี่ยนแปลงแม้แต่ฟิลด์เดียว ETag จะเปลี่ยน อย่างไรก็ตาม การคำนวณแฮชในทุกคำขอจะทำให้ CPU ทำงานหนัก — สำหรับระบบที่มีโหลดสูง ควรใช้หมายเลขเวอร์ชันที่เพิ่มขึ้น
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/"แฮช" | ความเท่าเทียมทางความหมาย | API JSON หน้าแบบไดนามิก |
ข้อจำกัดของ 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 ซึ่งป้องกันสภาวะการแข่งขัน: หากทรัพยากรเปลี่ยนแปลงระหว่างที่ไคลเอนต์ส่ง 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)
})
}
Middleware ใน Go สกัดกั้นคำขอ สร้าง ETag สำหรับ URL ที่ขอ (เช่น คำนวณแฮชข้อมูลจากแคชหรือ DB) และตั้งค่าหัวข้อการตอบสนอง หากไคลเอนต์ส่ง If-None-Match และตรงกับ ETag ปัจจุบัน เซิร์ฟเวอร์จะส่งคืน 304 Not Modified ทันที โดยไม่เรียกตัวจัดการหลัก ในระบบการผลิต ควรเพิ่มการแคชของ ETag ที่คำนวณแล้วตาม URL และพารามิเตอร์เพื่อลดภาระของเซิร์ฟเวอร์
ในการกำหนดค่าแบบหลายเซิร์ฟเวอร์ (round-robin หรือ anycast) ETag ต้อง เหมือนกัน บนทุกโหนดสำหรับทรัพยากรเดียวกัน หาก ETag สร้างตาม inode ของไฟล์และไซต์ถูกปรับใช้บนเซิร์ฟเวอร์หลายเครื่อง ค่าจะแตกต่างกัน วิธีแก้คือใช้แฮชเนื้อหาหรือพื้นที่เก็บข้อมูลเวอร์ชันส่วนกลาง (Redis, etcd) ปัญหาที่สองคือการบีบอัด gzip: Nginx เปลี่ยน ETag เมื่อเปิดใช้งานการบีบอัด ซึ่งอาจทำให้เกิดการตอบสนอง 304 ซ้ำซ้อน จำเป็นต้องกำหนดค่า gzip_vary on เพื่อซิงค์ ETag กับเนื้อหาที่ถูกบีบอัด
คำถามที่พบบ่อย
ได้ หากเซิร์ฟเวอร์ไม่ได้ป้องกันไว้อย่างชัดเจน ETag ไม่จำเป็นต้องไม่ซ้ำกันทั่วโลก — มันไม่ซ้ำกันภายใน URL ที่เฉพาะเจาะจง สำหรับไฟล์แบบคงที่ การชนกันไม่น่าเป็นไปได้เมื่อใช้แฮช SHA แต่ ตัวสร้างแบบกำหนดเอง อาจสร้างรายการที่ซ้ำกัน
ETag มีประสิทธิภาพมากที่สุดสำหรับทรัพยากรที่ถูกขอซ้ำ ๆ และไม่ค่อยเปลี่ยนแปลง: สินทรัพย์คงที่ รายการ API การกำหนดค่า สำหรับหน้าที่ไม่ซ้ำกันที่โหลด ครั้งเดียว (เช่น หน้ายืนยันคำสั่งซื้อ) ETag ไม่ให้ประโยชน์
CDN พิจารณา ETag ในการร้องขอต้นทางเพื่อตรวจสอบความสดของแคช หาก ETag ของทรัพยากรบนต้นทางเปลี่ยนแปลง CDN จะโหลดเวอร์ชันใหม่ Cloudflare และ Fastly รองรับ ETag เป็นกลไกการทำให้แคชเป็นโมฆะมาตรฐานในระดับต้นทาง
RFC 7232 ไม่จำกัดความยาวของ ETag แต่เซิร์ฟเวอร์และพร็อกซีอาจตัดหรือละเว้นค่าที่ยาวเกินไป แนะนำให้ใช้แฮช 20–40 ตัวอักษร หรือการรวมกันของตัวระบุเวอร์ชันและผลรวมตรวจสอบ
สิ่งเหล่านี้ไม่ใช่กลไกที่แยกจากกันโดยสิ้นเชิง Cache-Control กำหนดนโยบายการแคช (เก็บไว้นานเท่าใด ใครได้รับอนุญาต) ในขณะที่ ETag เป็นกลไก การตรวจสอบความถูกต้อง สำหรับทรัพยากรที่แคชไว้ การกำหนดค่าที่เหมาะสมที่สุดรวมหัวข้อทั้งสองไว้ด้วยกัน
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม