คู่มือ HTTP Caching: เร่งความเร็วเว็บไซต์โดยไม่ต้องเพิ่มโครงสร้างพื้นฐาน
เรียนรู้การใช้ Cache-Control headers, ETags, กลยุทธ์ CDN caching และพฤติกรรม browser cache เพื่อปรับปรุงเวลาโหลดเว็บไซต์และลดค่าใช้จ่ายเซิร์ฟเวอร์อย่างมีนัยสำคัญ
Caching คือการปรับแต่งประสิทธิภาพที่คุ้มค่าที่สุดที่คุณสามารถทำได้ การตอบสนองจาก cache จะเสร็จสิ้นภายในไม่กี่ไมโครวินาที ไม่มีต้นทุน และไม่ต้องใช้ทรัพยากรเซิร์ฟเวอร์เลย แต่แอปพลิเคชันส่วนใหญ่มักจะ cache มากเกินไป (ส่งเนื้อหาที่ล้าสมัย) หรือไม่ cache เลย (สิ้นเปลืองแบนด์วิดธ์และทรัพยากร) การเข้าใจ HTTP caching จะเปลี่ยนมันจากต้นเหตุของบั๊กให้กลายเป็นเครื่องมืออันทรงพลัง
HTTP caching ทำงานอย่างไร
เมื่อ browser หรือ CDN ได้รับการตอบสนอง ระบบจะตรวจสอบ headers เพื่อตัดสินใจว่าจะ cache หรือไม่ และจะ cache ไว้นานแค่ไหน เมื่อมีการร้องขอทรัพยากรเดิมครั้งต่อไป ระบบสามารถให้บริการสำเนาที่ cache ไว้ได้ทันที โดยไม่ต้องติดต่อเซิร์ฟเวอร์เลย
วงจรชีวิตของ cache มีสองช่วง:
- Freshness — สำเนาที่ cache ไว้ยังใช้งานได้อยู่ไหม? กำหนดโดย
Cache-Control: max-ageหรือExpires - Validation — หากหมดอายุ เราสามารถยืนยันกับเซิร์ฟเวอร์ว่าเนื้อหายังไม่เปลี่ยนแปลงได้ไหม? กำหนดโดย
ETagหรือLast-Modified
Cache-Control: directive หลักสำหรับการ caching
Cache-Control คือ caching header ที่ทรงพลังที่สุด เป็นรายการ directives คั่นด้วยเครื่องหมายจุลภาค:
Cache-Control: public, max-age=31536000, immutable
Directives สำคัญ
| Directive | ความหมาย |
|---|---|
public |
Cache ใดก็ได้ (browser, CDN, proxy) สามารถเก็บข้อมูลนี้ได้ |
private |
เฉพาะ browser ของผู้ใช้เท่านั้นที่ cache ได้ (ไม่ใช่ CDN) |
no-cache |
ต้องยืนยันกับเซิร์ฟเวอร์ก่อนใช้งานทุกครั้ง (ไม่ได้หมายความว่า "ห้าม cache") |
no-store |
ห้าม cache เด็ดขาด — สำหรับข้อมูลที่ละเอียดอ่อน |
max-age=N |
Cache เป็นเวลา N วินาที |
s-maxage=N |
max age เฉพาะ CDN (แทนที่ max-age สำหรับ shared caches) |
immutable |
เนื้อหาจะไม่มีการเปลี่ยนแปลง — ข้ามการ revalidation ทั้งหมด |
must-revalidate |
เมื่อหมดอายุ ต้อง revalidate ก่อนให้บริการ |
stale-while-revalidate=N |
ให้บริการข้อมูลเก่าเป็นเวลา N วินาที ขณะดึงข้อมูลใหม่ในเบื้องหลัง |
⚠️
no-cacheไม่ได้หมายความว่า "ห้าม cache" แต่หมายความว่า "cache ไว้ แต่ตรวจสอบเสมอว่ายังใช้งานได้อยู่ไหม" ใช้no-storeหากคุณไม่ต้องการให้ cache จริงๆ
กลยุทธ์การ caching ตามประเภทของทรัพยากร
ทรัพยากรแต่ละประเภทต้องการกลยุทธ์ที่แตกต่างกัน:
Static assets ที่ใช้ content hashing (CSS, JS, รูปภาพ)
Cache-Control: public, max-age=31536000, immutable
หาก build tool ของคุณเพิ่ม hash ไว้ในชื่อไฟล์ (main.a3f9b2c.js) URL จะเปลี่ยนเมื่อเนื้อหาเปลี่ยน สามารถ cache ไว้ตลอดไปได้ เพราะเวอร์ชันใหม่จะมี URL ใหม่เสมอ
HTML pages
Cache-Control: no-cache
หรือจะกำหนด TTL สั้นๆ:
Cache-Control: public, max-age=60, stale-while-revalidate=3600
HTML มีการเปลี่ยนแปลงบ่อยและลิงก์ไปยัง assets ที่มี hash ควร cache ไว้ช่วงสั้นๆ หรือบังคับให้ revalidate
API responses
# ข้อมูลสาธารณะ (เช่น แคตาล็อกสินค้า)
Cache-Control: public, max-age=300, stale-while-revalidate=600
# ข้อมูลเฉพาะผู้ใช้
Cache-Control: private, max-age=60
# ข้อมูลเรียลไทม์ (ราคาหุ้น, คะแนนสด)
Cache-Control: no-store
ข้อมูลที่ละเอียดอ่อน (การยืนยันตัวตน, การชำระเงิน)
Cache-Control: no-store
ห้าม cache ทุกกรณี
ETags และ conditional requests
เมื่อ cached response หมดอายุ browser ไม่ได้ทิ้งมันไปทันที แต่จะถามเซิร์ฟเวอร์ว่ายังใช้งานได้อยู่ไหม นี่คือ revalidation
ETags
ETag คือลายนิ้วมือของเนื้อหาที่ตอบสนอง:
# เซิร์ฟเวอร์ส่ง:
ETag: "a3f9b2c8d4e1"
# คำขอครั้งต่อไปของ browser:
If-None-Match: "a3f9b2c8d4e1"
# หากไม่มีการเปลี่ยนแปลง เซิร์ฟเวอร์ตอบสนองด้วย:
HTTP/1.1 304 Not Modified
(ไม่มี body — ประหยัดแบนด์วิดธ์)
# หากมีการเปลี่ยนแปลง เซิร์ฟเวอร์ตอบสนองด้วย:
HTTP/1.1 200 OK
ETag: "b7c2d4e9a1f3"
(การตอบสนองใหม่เต็มรูปแบบ)
การตอบสนอง 304 Not Modified ไม่มี body — มีเพียง headers เท่านั้น ซึ่งช่วยประหยัดแบนด์วิดธ์ในการดาวน์โหลดเนื้อหาซ้ำได้ทั้งหมด
Last-Modified
คล้ายกันแต่ใช้ timestamp แทน hash:
Last-Modified: Tue, 01 Apr 2026 10:00:00 GMT
# Browser ส่ง:
If-Modified-Since: Tue, 01 Apr 2026 10:00:00 GMT
ETags มีความน่าเชื่อถือมากกว่า (timestamps อาจไม่แม่นยำเมื่อใช้ load-balanced servers)
Vary header: cache แยกตามตัวแปรของคำขอ
Vary header บอก caches ว่า request headers ใดที่ส่งผลต่อการตอบสนอง:
Vary: Accept-Encoding
นี่จะ cache สำเนาแยกกันสำหรับการตอบสนองแบบ gzip และ br การใช้งานทั่วไป:
Vary: Accept-Encoding # Cache แยกสำหรับแบบบีบอัดและไม่บีบอัด
Vary: Accept-Language # Cache แยกตามภาษา
Vary: Accept # Cache แยกสำหรับการตอบสนองแบบ JSON และ HTML
⚠️
Vary: CookieหรือVary: Authorizationจะปิดการใช้งาน CDN caching โดยพฤตินัย เนื่องจาก CDN ไม่สามารถ cache การตอบสนองที่เฉพาะเจาะจงต่อผู้ใช้ได้
stale-while-revalidate: การรีเฟรชในเบื้องหลัง
หนึ่งในรูปแบบ caching สมัยใหม่ที่มีประโยชน์มากที่สุด:
Cache-Control: max-age=60, stale-while-revalidate=600
- ให้บริการจาก cache ทันทีใน 60 วินาทีแรก (fresh)
- สำหรับคำขอระหว่าง 60–660 วินาที: ให้บริการสำเนาที่หมดอายุทันที แต่ดึงเวอร์ชันใหม่ในเบื้องหลัง
- หลัง 660 วินาที: ต้อง revalidate ก่อนให้บริการ
ผู้ใช้จะได้รับการตอบสนองที่รวดเร็วเสมอ และ cache ก็ยังคงความสดใหม่โดยไม่บังคับให้ใครต้องรอการเชื่อมต่อเครือข่าย
ข้อควรพิจารณาสำหรับ CDN caching
CDN (Cloudflare, CloudFront, Fastly) เคารพ Cache-Control headers แต่เพิ่มความซับซ้อนอีกชั้น:
-
s-maxageช่วยให้คุณกำหนด TTL ที่แตกต่างกันสำหรับ CDN กับ browser:Cache-Control: public, max-age=60, s-maxage=86400Browser cache ไว้ 1 นาที; CDN cache ไว้ 24 ชั่วโมง
-
Cache purging — เมื่อคุณ deploy ให้ purge CDN cache สำหรับ assets ที่อัปเดตแล้ว CDN ส่วนใหญ่รองรับการ purging ผ่าน API
-
Cache keys — CDN จะ cache ตาม URL + Vary headers โดย query strings มักถูกรวมอยู่ใน cache key ด้วย
การทดสอบพฤติกรรมของ cache
ใช้ API Request Builder ของเราเพื่อตรวจสอบ response headers และยืนยันว่าการตั้งค่า caching ของคุณทำงานได้ถูกต้อง:
- ส่งคำขอและตรวจสอบ headers
Cache-Control,ETagและLast-Modified - ส่งคำขอเดิมอีกครั้ง — ตรวจสอบ
Ageheader (วินาทีนับตั้งแต่ cache) และX-Cache: HIT - ตรวจสอบ
CF-Cache-Status(Cloudflare) หรือX-Cache(CloudFront) เพื่อยืนยัน CDN caching
ใน Chrome DevTools → แท็บ Network → คลิกทรัพยากร → แท็บ Headers — ดูหา from disk cache หรือ from memory cache ในการตอบสนอง
การกำหนดค่า Nginx caching
กำหนดค่า caching headers ที่ระดับ Nginx เพื่อให้มีพฤติกรรมที่สอดคล้องกัน:
# Static assets — cache ตลอดไป
location ~* \.(js|css|woff2|png|jpg|webp|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML — revalidate เสมอ
location ~* \.html$ {
add_header Cache-Control "no-cache";
}
# API — cache สั้นพร้อม stale-while-revalidate
location /api/ {
add_header Cache-Control "public, max-age=60, stale-while-revalidate=600";
}
ใช้ Nginx Config Generator ของเราเพื่อสร้างการกำหนดค่า Nginx ที่สมบูรณ์และเหมาะสมที่สุดสำหรับกรณีการใช้งานของคุณ
Caching checklist
- Static assets (CSS/JS) ใช้ชื่อไฟล์แบบ content-hashed +
max-age=31536000, immutable - HTML ให้บริการด้วย
no-cacheหรือmax-ageที่สั้นมาก - API responses ถูก cache ตามความถี่ในการอัปเดต
- ข้อมูลที่ละเอียดอ่อนใช้
no-store - เปิดใช้งาน ETags หรือ
Last-Modifiedสำหรับ conditional requests - ใช้
stale-while-revalidateกับ API endpoints ที่เหมาะสม - ยืนยันและทดสอบ CDN caching headers แล้ว
การทำ HTTP caching อย่างถูกต้องจะทำให้เว็บไซต์ของคุณรู้สึกเร็วทันทีสำหรับผู้เยี่ยมชมที่กลับมา ลดค่าใช้จ่ายด้านแบนด์วิดธ์ และลดภาระเซิร์ฟเวอร์ — ทั้งหมดนี้โดยไม่ต้องเพิ่มโครงสร้างพื้นฐานใดๆ