Conditional GET — กลไก HTTP ที่ช่วยให้ไคลเอ็นต์ตรวจสอบความสดใหม่ของทรัพยากรที่ถูกแคชไว้ก่อนการดาวน์โหลดเต็มรูปแบบ ไคลเอ็นต์ส่งคำขอ GET พร้อมส่วนหัว If-None-Match (ซึ่งมี ETag) หรือ If-Modified-Since (ซึ่งมีวันที่) และเซิร์ฟเวอร์จะส่งคืน 304 Not Modified โดยไม่มีเนื้อหาการตอบกลับหากทรัพยากรไม่มีการเปลี่ยนแปลง ตาม MDN Web Docs, 2025 คำขอแบบมีเงื่อนไขช่วยลดปริมาณการรับส่งข้อมูลเครือข่ายของเซิร์ฟเวอร์และไคลเอ็นต์ 304 Not Modified เป็นสถานะ HTTP ที่สำคัญสำหรับการซิงโครไนซ์แอปพลิเคชันมือถืออย่างมีประสิทธิภาพ
ประเด็นสำคัญ
Conditional GET คือคำขอ GET ที่มีส่วนหัวแบบมีเงื่อนไขหนึ่งรายการขึ้นไป ซึ่งเซิร์ฟเวอร์จะใช้ตัดสินใจว่าจะส่งคืนการตอบสนองแบบเต็มหรือเพียงสถานะ 304 Not Modified เป้าหมายหลักคือหลีกเลี่ยงการส่งเนื้อหาการตอบกลับหากทรัพยากรไม่มีการเปลี่ยนแปลงตั้งแต่คำขอครั้งล่าสุด นี่เป็นกลไกการแคช HTTP พื้นฐานที่กำหนดใน RFC 7232
สำหรับแอปพลิเคชันมือถือ Conditional GET เป็นหนึ่งในวิธีที่มีประสิทธิภาพที่สุดในการ เพิ่มประสิทธิภาพปริมาณการใช้เครือข่าย สถานการณ์ทั่วไป: เมื่อเปิดแอป ไคลเอ็นต์จะส่งชุดคำขอ GET แบบมีเงื่อนไขเพื่อโหลดฟีด โปรไฟล์ และการตั้งค่า หากข้อมูลไม่มีการเปลี่ยนแปลง แอปจะได้รับ 304 และใช้สำเนาท้องถิ่น ใช้เวลาเป็นมิลลิวินาทีแทนที่จะเป็นวินาทีและไม่ใช้ข้อมูลมือถือ
ตาม Google Web Fundamentals (2025) การใช้คำขอ GET แบบมีเงื่อนไขในแอปพลิเคชันมือถือช่วยลดเวลาในการโหลดเฉลี่ยลง 40–60% สำหรับการเข้าชมซ้ำ และลดการใช้ปริมาณการรับส่งข้อมูลลง 70–90% สำหรับหน้าที่มีการอัปเดตไม่บ่อย ผลกระทบจะสังเกตเห็นได้ชัดเจนโดยเฉพาะบนการเชื่อมต่อที่ช้า (3G, Edge) ซึ่งทุกไบต์มีความสำคัญ
กระบวนการประกอบด้วยสามขั้นตอน ขั้นตอนแรก — ไคลเอ็นต์ส่งคำขอ GET ทั่วไป เซิร์ฟเวอร์ส่งคืนทรัพยากรพร้อมกับส่วนหัวการแคช (ETag, Last-Modified) ขั้นตอนที่สอง — ไคลเอ็นต์บันทึกทรัพยากรและตัวตรวจสอบไว้ในเครื่อง ขั้นตอนที่สาม — เมื่อมีการร้องขอซ้ำ ไคลเอ็นต์ส่ง GET พร้อม If-None-Match (สำหรับ ETag) และ/หรือ If-Modified-Since (สำหรับ Last-Modified) เซิร์ฟเวอร์ตรวจสอบตัวตรวจสอบและตอบกลับ 304 หากทรัพยากรไม่มีการเปลี่ยนแปลง หรือ 200 พร้อมข้อมูลใหม่
เซิร์ฟเวอร์ใช้ ลำดับความสำคัญของ ETag มากกว่า Last-Modified เมื่อมีทั้งสองส่วนหัว เนื่องจาก ETag ให้การตรวจสอบที่แม่นยำกว่า — แฮชเนื้อหาเปลี่ยนแปลงตามการแก้ไขใดๆ ในขณะที่ Last-Modified มีความละเอียดหนึ่งวินาที หาก ETag ตรงกัน เซิร์ฟเวอร์จะส่งคืน 304 ทันทีโดยไม่ต้องตรวจสอบ Last-Modified
ตัวอย่างของวงจร Conditional GET ที่สมบูรณ์ในลำดับคำขอ:
// ขั้นตอนที่ 1: คำขอแรก — รับข้อมูลและ ETag
GET /api/profile
Response: 200 OK
ETag: "33a64df551425fcc55e"
Body: { "name": "Alice" }
// ขั้นตอนที่ 2: ทำคำขอซ้ำ — ด้วย If-None-Match
GET /api/profile
If-None-Match: "33a64df551425fcc55e"
Response: 304 Not Modified
// เนื้อหาการตอบรับไม่มี — ใช้สำเนาท้องถิ่น
ในคำขอที่สอง เซิร์ฟเวอร์เปรียบเทียบ ETag จาก If-None-Match กับแฮชทรัพยากรปัจจุบัน หากตรงกัน เซิร์ฟเวอร์จะส่งคืน 304 โดยไม่มีเนื้อหา — ไคลเอ็นต์ยังคงใช้ข้อมูลที่ถูกแคชไว้ นี่คือสาระสำคัญของ Conditional GET: ปริมาณการรับส่งข้อมูลน้อยที่สุดกับความสดใหม่ของข้อมูลสูงสุด
คำขอ GET ทั่วไป จะส่งคืนการตอบสนอง 200 OK แบบเต็มพร้อมเนื้อหาเสมอ แม้ว่าทรัพยากรจะไม่มีการเปลี่ยนแปลง เซิร์ฟเวอร์ก็จะส่งข้อมูลทั้งหมดอีกครั้ง ซึ่งยอมรับได้สำหรับทรัพยากรขนาดเล็กหรือคำขอที่ไม่บ่อยนัก แต่สำหรับแอปพลิเคชันมือถือที่มีคำขอหลายร้อยครั้งในการเปิดแต่ละครั้ง วิธีนี้นำไปสู่การใช้ปริมาณการรับส่งข้อมูลและแบตเตอรี่มากเกินไป
Conditional GET เพิ่มค่าใช้จ่ายในรูปแบบของส่วนหัว (โดยปกติ 50–200 ไบต์ต่อคำขอ) แต่ประหยัดกิโลไบต์และเมกะไบต์ด้วยการตอบสนอง 304 ยิ่งทรัพยากรมีขนาดใหญ่เท่าใด คำขอแบบมีเงื่อนไขก็ยิ่งมีประโยชน์มากขึ้นเท่านั้น สำหรับรูปภาพ รายการข้อมูล และเอกสาร JSON ตั้งแต่ 10 KB ขึ้นไป Conditional GET คุ้มค่าตั้งแต่คำขอซ้ำครั้งแรก
ลักษณะเปรียบเทียบของทั้งสองวิธี:
| พารามิเตอร์ | GET ทั่วไป | Conditional GET |
|---|---|---|
| ปริมาณการรับส่งข้อมูล (ไม่มีการเปลี่ยนแปลง) | การตอบสนองแบบเต็ม | เฉพาะส่วนหัว (~200 ไบต์) |
| ความหน่วง | ดาวน์โหลดเต็ม | มิลลิวินาที (304) |
| โหลดเซิร์ฟเวอร์ | สร้าง + ส่ง | ตรวจสอบ ETag เท่านั้น |
| ความซับซ้อนในการใช้งาน | น้อยที่สุด | ต้องการจัดเก็บ ETag |
| ประสิทธิภาพสำหรับข้อมูลขนาดใหญ่ | ต่ำ | สูง |
มาดูการใช้งานแบบเต็มรูปแบบ ของ Conditional GET ใน Kotlin โดยใช้ OkHttp และ Room สำหรับจัดเก็บ ETag แอปพลิเคชันรายการงานโหลดงานจากเซิร์ฟเวอร์และใช้คำขอแบบมีเงื่อนไขเพื่อลดปริมาณการรับส่งข้อมูล ETag ถูกจัดเก็บในฐานข้อมูลท้องถิ่นเพื่อคงอยู่ระหว่างเซสชัน
พื้นที่เก็บข้อมูลที่มี Conditional GET ใน Kotlin:
class TaskRepository(
private val api: TaskApi,
private val etagDao: EtagDao
) {
suspend fun getTasks(): List<Task> {
val savedEtag = etagDao.getEtag("tasks")
val response = api.fetchTasks(
ifNoneMatch = savedEtag
)
return when (response.code()) {
304 -> taskDao.getAll() // จากแคชท้องถิ่น
200 -> {
response.header("ETag")?.let {
etagDao.saveEtag("tasks", it)
}
val tasks = response.body() ?: emptyList()
taskDao.replaceAll(tasks)
tasks
}
else -> throw Exception(
"Sync failed: ${response.code()}")
}
}
}
TaskRepository ตรวจสอบรหัสการตอบสนอง: 304 หมายถึงไม่มีการเปลี่ยนแปลง และข้อมูลจะถูกส่งคืนจากแคช Room ในเครื่อง เมื่อ 200 ETag ใหม่จะถูกบันทึกและงานจะถูกอัปเดตในฐานข้อมูลท้องถิ่น รูปแบบนี้เป็นมาตรฐานสำหรับแอปพลิเคชันมือถือที่มีการซิงโครไนซ์ผ่าน REST API
Conditional GET ถูกใช้อย่างแพร่หลาย ในแอปพลิเคชันมือถือเพื่อเพิ่มประสิทธิภาพการซิงโครไนซ์ข้อมูล สถานการณ์หลัก: โหลดฟีดข่าว (Twitter, Instagram สอบถาม API เป็นระยะด้วย If-None-Match), อัปเดตโปรไฟล์ผู้ใช้, โหลดรายการการแจ้งเตือน และซิงโครไนซ์งาน ในแต่ละกรณี แอปสามารถตรวจสอบความสดใหม่ของข้อมูลโดยไม่ต้องดาวน์โหลดซ้ำ
สำหรับ แอปพลิเคชันที่เน้นการทำงานแบบออฟไลน์ Conditional GET ทำหน้าที่เป็นขั้นตอนแรกของการซิงโครไนซ์ แอปจะส่งคำขอ GET แบบมีเงื่อนไขก่อนสำหรับทรัพยากรทั้งหมดที่ถูกแก้ไขในเครื่องตั้งแต่การซิงโครไนซ์ครั้งล่าสุด ทรัพยากรที่มี 304 ไม่จำเป็นต้องดาวน์โหลด หลังจากนั้น แอปจะส่ง PUT/POST สำหรับการเปลี่ยนแปลงในเครื่อง วิธีการสองขั้นตอนนี้ช่วยให้มั่นใจได้ถึงการใช้ปริมาณการรับส่งข้อมูลน้อยที่สุด
เมื่อรวมกับ การแก้ไขข้อขัดแย้ง Conditional GET ช่วยให้ตรวจจับข้อขัดแย้งได้อย่างมีประสิทธิภาพ หากไคลเอ็นต์ได้รับ 200 พร้อมข้อมูลใหม่ (ทรัพยากรมีการเปลี่ยนแปลง) แต่มีการเปลี่ยนแปลงในเครื่องที่ยังไม่ได้ส่ง — จะมีการบันทึกข้อขัดแย้ง ไคลเอ็นต์สามารถใช้ LWW (การเปลี่ยนแปลงในเครื่องจะสูญหาย) หรือเริ่มกลยุทธ์การรวมเพื่อรวมการเปลี่ยนแปลงในเครื่องและระยะไกล ตาม Meta Engineering Blog (2025) การใช้ Conditional GET ใน Messenger ช่วยลดปริมาณการรับส่งข้อมูลการซิงโครไนซ์เฉลี่ยลง 73%
คำถามที่พบบ่อย
Conditional GET — คำขอ HTTP GET พร้อมส่วนหัวแบบมีเงื่อนไข (If-None-Match, If-Modified-Since) เซิร์ฟเวอร์ส่งคืน 304 Not Modified หากทรัพยากรไม่มีการเปลี่ยนแปลง หรือ 200 พร้อมข้อมูลใหม่ นี่คือกลไกการแคชที่มีประสิทธิภาพ
GET ทั่วไป จะส่งคืนการตอบสนองแบบเต็มพร้อมเนื้อหาเสมอ Conditional GET เพิ่มส่วนหัวตรวจสอบเวอร์ชัน (ETag, วันที่) หากข้อมูลไม่มีการเปลี่ยนแปลง เซิร์ฟเวอร์จะตอบสนอง 304 โดยไม่มีเนื้อหา ประหยัดปริมาณการรับส่งข้อมูลและเวลาในการโหลด
สำหรับการแคชที่มีประสิทธิภาพ ให้บันทึก ETag และ Last-Modified จากการตอบสนองของเซิร์ฟเวอร์แต่ละครั้งในฐานข้อมูลท้องถิ่น ในการขอครั้งถัดไป ให้ส่งในส่วนหัว If-None-Match และ If-Modified-Since เมื่อได้ 304 ให้ใช้ข้อมูลจากแคชในเครื่อง
เมื่อได้รับการตอบสนอง 304 เซิร์ฟเวอร์จะไม่ส่งเนื้อหาการตอบกลับ — เฉพาะส่วนหัว (~200 ไบต์) สำหรับทรัพยากรขนาด 50 KB หมายถึงการประหยัดปริมาณการรับส่งข้อมูล 99.6% สำหรับแอปที่ซิงโครไนซ์ 50 ครั้งต่อวัน การประหยัดถึงสิบเมกะไบต์ต่อเดือน
ใช่ นี่เป็นวิธีมาตรฐาน สำหรับการซิงโครไนซ์แบบเดลต้า ไคลเอ็นต์ตรวจสอบความสดใหม่ของทรัพยากรแต่ละรายการผ่าน Conditional GET ดาวน์โหลดเฉพาะทรัพยากรที่มีการเปลี่ยนแปลง และส่งการเปลี่ยนแปลงในเครื่อง วิธีนี้ใช้ใน Twitter, Instagram, Telegram และ API ที่ทันสมัยส่วนใหญ่
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ