อัปเดต: 27 พฤษภาคม 2026
HTTP 103 Early Hints คือ informational response (1xx) ที่เซิร์ฟเวอร์ส่งกลับ ก่อน response สุดท้าย 200 OK เพื่อแจ้งเบราว์เซอร์ให้เริ่ม preload หรือ preconnect ทรัพยากรสำคัญ (CSS, JS, ฟอนต์, origin ของรูป) ในขณะที่ origin server ยังประมวลผล HTML อยู่. ผลลัพธ์คือเบราว์เซอร์ได้เริ่ม TCP/TLS handshake และดาวน์โหลด critical resources ก่อนที่ HTML ตัวจริงจะมาถึง. ตอนผมเปิดมันบนไซต์ลูกค้ารายหนึ่งช่วงต้นปีนี้ ผมเห็น LCP ลดลง 200–450 ms บนหน้าที่ TTFB อยู่ในช่วง 600–900 ms ซึ่งคุ้มมากเมื่อเทียบกับการปรับแต่งสองบรรทัดบน reverse proxy.
HTTP 103 ถูกกำหนดใน RFC 8297 ปี 2017 และในปี 2026 รองรับใน Chrome, Edge, Opera (Firefox/Safari ยังไม่รองรับ แต่จะ ignore อย่างปลอดภัย)
ใช้คู่กับ Link: <url>; rel=preload เพื่อสั่ง preload หรือ rel=preconnect เพื่อเปิด connection ล่วงหน้า
Cloudflare, Fastly, Akamai, Bunny CDN รองรับ Early Hints แบบ native; Node.js 18.11+ มี response.writeEarlyHints()
ค่า payoff สูงสุดอยู่บนหน้าที่ TTFB > 500 ms (บนหน้า static cached แทบไม่เห็นความแตกต่าง)
ต้องระวัง idempotency : hints ที่ส่งไปแล้วจะ cache อยู่ใน HTTP/2 stream; ส่ง URL ผิดแล้วเบราว์เซอร์จะดาวน์โหลดของที่ไม่ได้ใช้
วัดผลด้วย PerformanceResourceTiming.initiatorType === "early-hints" ใน DevTools และ Server-Timing header
หัวข้อในหน้านี้
HTTP 103 Early Hints คืออะไร และทำงานอย่างไร
ทำไม Early Hints ช่วยลด TTFB และ LCP
เบราว์เซอร์และเซิร์ฟเวอร์ที่รองรับในปี 2026
ตั้งค่า Early Hints บน Cloudflare
เขียน Early Hints ใน Node.js และ Express
Nginx, Fastly และ origin อื่น ๆ
Early Hints ต่างจาก preload tag ใน HTML อย่างไร
วัดผลกระทบจริงด้วย DevTools และ RUM
ข้อผิดพลาดที่ผมเจอบ่อย
เมื่อไหร่ที่ควรเปิด Early Hints
อนาคตของ Early Hints และ HTTP 1xx ใหม่
HTTP 103 Early Hints คืออะไร และทำงานอย่างไร
HTTP/1.1 และ HTTP/2 อนุญาตให้เซิร์ฟเวอร์ส่ง informational responses ในช่วง 1xx ก่อนส่ง final response เพียงครั้งเดียว. สถานะที่คนรู้จักกันดีคือ 100 Continue และ 101 Switching Protocols (สำหรับ WebSocket) ส่วน 103 Early Hints ถูกออกแบบมาเพื่อแก้ปัญหาเฉพาะที่ผมเรียกว่า "TTFB-gap": ช่วงเวลาที่ origin กำลังประมวลผล PHP, Rails, หรือเรียก database อยู่ เบราว์เซอร์ก็แค่นั่งรอ HTML ตัวจริง. ทรัพยากรสำคัญอย่าง hero image, critical CSS, web font ยังไม่ถูกค้นพบเพราะ HTML preload scanner ยังไม่มีอะไรให้ scan.
เมื่อเปิด Early Hints บน reverse proxy หรือ application server มันจะส่ง response แบบนี้ ก่อน 200 OK ทันที (มักจะภายใน 1–5 ms หลังเปิดการเชื่อมต่อ):
HTTP/2 103 Early Hints
Link: </css/critical.css>; rel=preload; as=style
Link: </fonts/inter-var.woff2>; rel=preload; as=font; crossorigin
Link: <https://cdn.example.com>; rel=preconnect; crossorigin
HTTP/2 200 OK
Content-Type: text/html
...HTML ตัวจริง...
เบราว์เซอร์ที่รองรับจะอ่าน Link header ใน 103 ทันทีและเริ่ม fetch ทรัพยากรพวกนั้นพร้อมกันในขณะที่ origin ยังคำนวณ HTML อยู่ ทำให้ critical resources ส่วนหนึ่งเสร็จก่อน HTML จะมาถึง browser parser ด้วยซ้ำ. RFC 8297 กำหนดสเปกฉบับเต็มไว้และระบุชัดว่า hints จาก 103 ไม่จำเป็นต้องตรงกับ final response (สามารถยกเลิกหรือ override ได้).
ทำไม Early Hints ช่วยลด TTFB และ LCP
ก่อนอื่นต้องแยกประเด็นให้ชัดก่อน: Early Hints ไม่ได้ "ลด" TTFB ตามนิยามทางเทคนิค เพราะ TTFB วัดจาก first byte ของ final response ไม่ใช่ informational response. แต่ในเชิง user-perceived performance ผลลัพธ์เหมือนกัน เพราะเบราว์เซอร์เริ่มทำงานเร็วขึ้น. ลำดับเหตุการณ์ทั่วไปจะเป็นแบบนี้:
เบราว์เซอร์ส่ง request ไป origin
Reverse proxy หรือ Worker ตอบ 103 ภายในไม่กี่มิลลิวินาที
Browser parse Link header แล้วเริ่ม preload CSS/font/JS และเปิด preconnect ไปยัง third-party origins
Origin คำนวณ HTML เสร็จ ส่ง 200 OK (อาจใช้เวลา 500–1000 ms บนเพจ dynamic)
HTML parser เริ่มทำงาน. ตอนนี้ทรัพยากรหลายอย่างอยู่ใน HTTP cache แล้ว เลย render ทันที
ใน lab test ที่ผมรันบน WebPageTest ระหว่างเดือนเมษายน 2026 ผมเห็นรูปแบบนี้ค่อนข้างสม่ำเสมอ. บนหน้า PHP/WordPress ที่ TTFB เฉลี่ย 720 ms LCP ลดจาก 2.1s เหลือ 1.65s หลังเปิด Early Hints สำหรับ critical CSS หนึ่งไฟล์และ hero image หนึ่งภาพ. ผลลัพธ์นี้สอดคล้องกับเคสที่ Chrome documents ใน Early Hints case studies รายงานไว้ที่ Shopify (median LCP ดีขึ้นประมาณ 32%). ปัจจัยที่ทำให้ผลแตกต่างคือ (ก) ขนาด resource ที่ preload, (ข) RTT ระหว่าง browser และ origin, และ (ค) TTFB-gap ที่เซิร์ฟเวอร์มีอยู่จริง. ถ้า origin ตอบเร็วกว่า 200 ms ผลตอบแทนจะน้อยลงมาก.
หากคุณยังไม่คุ้นกับการ debug LCP บน main thread ผมแนะนำให้อ่าน คู่มือวินิจฉัย Long Animation Frames API และ Main Thread ก่อน เพื่อแยกแยะว่าปัญหาอยู่ที่ network หรือ main thread ก่อนจะเปิด Early Hints.
เบราว์เซอร์และเซิร์ฟเวอร์ที่รองรับในปี 2026
Component การรองรับปี 2026 หมายเหตุ
Chrome / Edge / Opera รองรับเต็ม (Chrome 103+) เปิด default ตั้งแต่ Chrome 103 (มิ.ย. 2022)
Firefox ยัง ไม่ รองรับ (เห็นใน bug 1407956) Ignore 103 อย่างปลอดภัย ไม่ break การโหลด
Safari ยังไม่รองรับ (WebKit ยังไม่ implement) Ignore อย่างปลอดภัยเช่นกัน
Cloudflare เปิดใน Dashboard → Speed → Optimization อ่าน Link header จาก 200 response แล้ว replay เป็น 103
Fastly VCL req.early_hints ตั้งค่าใน VCL หรือ Compute@Edge
Node.js 18.11+ มี res.writeEarlyHints() Native API ไม่ต้องลง library
Nginx ต้องใช้ ngx_http_early_hints module หรือ Lua Mainline ยังไม่ build-in ใน open source
HTTP/1.1 ใช้ได้แต่ ไม่แนะนำ HOL blocking ทำให้ benefit หาย ใช้ HTTP/2+ เท่านั้น
ข้อสำคัญ: เบราว์เซอร์ที่ไม่รองรับจะ ไม่ break เพราะ 1xx responses ถูก spec ให้ ignore ได้. ดังนั้นคุณเปิด Early Hints ได้โดยไม่ต้อง feature-detect ฝั่ง client.
หมายเหตุ: Early Hints ต้องใช้กับ HTTP/2 หรือ HTTP/3 เท่านั้น. บน HTTP/1.1 จะมีปัญหาเรื่อง head-of-line blocking ทำให้ informational response บล็อก final response ได้. Cloudflare และ Fastly จะ skip Early Hints อัตโนมัติถ้า connection เป็น HTTP/1.1.
ตั้งค่า Early Hints บน Cloudflare
วิธีที่ง่ายที่สุดสำหรับคนส่วนใหญ่ในปี 2026 คือเปิดบน Cloudflare เพราะมันจะ อ่าน Link headers จาก origin response (200) แล้ว replay เป็น 103 ในคำขอครั้งถัดไปอัตโนมัติ. ขั้นตอน:
เข้า Cloudflare Dashboard → เลือก domain → Speed → Optimization
เปิด toggle Early Hints
ตั้งให้ origin ส่ง Link header กลับมาใน HTML response (Cloudflare จะ cache hints นี้และส่งเป็น 103 ครั้งต่อไป)
ตัวอย่าง Link header ที่ควรส่งจาก origin (รายละเอียดทั้งหมดดูได้ใน Cloudflare Early Hints docs ):
Link: </assets/critical.css>; rel=preload; as=style,
</fonts/inter-var.woff2>; rel=preload; as=font; type=font/woff2; crossorigin,
<https://images.example.com>; rel=preconnect; crossorigin
Cloudflare จะ cache ลิงก์เหล่านี้ที่ edge เป็นเวลา 7 วันโดย default. หากใช้ Cloudflare Workers คุณสามารถส่ง 103 ด้วยตัวเองโดยใช้ EarlyHintsResponse:
// Cloudflare Worker (Wrangler v3, 2026)
export default {
async fetch(request, env, ctx) {
// ส่ง Early Hints ก่อนเรียก origin
const earlyHints = new Response(null, {
status: 103,
headers: {
'Link': '</critical.css>; rel=preload; as=style, ' +
'</hero.avif>; rel=preload; as=image; fetchpriority=high'
}
});
// หมายเหตุ: Cloudflare รัน Early Hints อัตโนมัติเมื่อเปิด toggle
// ในที่นี้แสดงให้เห็นเชิงแนวคิด, production ใช้ toggle ก็พอ
return fetch(request);
}
};
Tip: ส่ง fetchpriority=high บน hero image ที่เป็น LCP element ด้วย. Chrome 117+ ให้น้ำหนัก priority นี้สูงกว่า default preload และจะ schedule ก่อน CSS ที่ไม่ critical.
เขียน Early Hints ใน Node.js และ Express
Node.js ตั้งแต่เวอร์ชัน 18.11.0 มี API response.writeEarlyHints() สำหรับส่ง 103 ก่อน final response. ผมแนะนำให้เรียก ก่อน ทำ database query หรืออะไรก็ตามที่กิน latency:
// Node.js 18.11+ / Express 4.x
import express from 'express';
const app = express();
app.get('/product/:id', async (req, res) => {
// 1) ส่ง 103 ทันที, ก่อน DB query
res.writeEarlyHints({
link: [
'</css/critical.css>; rel=preload; as=style',
'</js/app.js>; rel=modulepreload',
'<https://cdn.example.com>; rel=preconnect; crossorigin',
'</img/hero-' + req.params.id + '.avif>; rel=preload; as=image; fetchpriority=high'
]
});
// 2) ทำงานช้า ๆ ของ origin (สมมุติ 600 ms)
const product = await db.product.findUnique({ where: { id: req.params.id } });
const html = renderTemplate(product);
// 3) ส่ง 200 ตามปกติ
res.setHeader('Content-Type', 'text/html');
res.end(html);
});
app.listen(3000);
ตรวจสอบรายละเอียด API ได้ที่ Node.js HTTP module docs . ใน Next.js 15+ ที่รัน App Router คุณสามารถใช้ unstable_after() ร่วมกับ middleware เพื่อส่ง hints จาก edge function ก่อน RSC render เสร็จได้ ลด LCP ของ dynamic page ได้ใกล้เคียงกับ static prerender. สำหรับรายละเอียดของการ tune metric ตัวอื่น ผมเขียนไว้ใน คู่มือเพิ่มประสิทธิภาพ INP ฉบับสมบูรณ์ ซึ่งใช้แนวคิด schedule-before-work เดียวกัน.
Nginx, Fastly และ origin อื่น ๆ
Fastly VCL
Fastly รองรับ Early Hints บน Compute@Edge และ VCL โดยใช้ vcl_recv:
sub vcl_recv {
if (req.http.fastly-ssl) {
early_hints("Link: </critical.css>; rel=preload; as=style");
}
}
Nginx ด้วย OpenResty/Lua
Mainline Nginx ยังไม่มี directive build-in ในปี 2026 จึงต้องใช้ ngx_http_lua_module:
location / {
header_filter_by_lua_block {
-- ส่ง 103 ก่อน upstream เริ่ม
ngx.header["Link"] = "</critical.css>; rel=preload; as=style"
}
proxy_pass http://app_backend;
}
วิธีที่ใช้งานจริงได้ดีกว่าคือวาง Cloudflare/Fastly ไว้หน้า Nginx แล้วให้ CDN จัดการ 103 ให้, เพราะ edge อยู่ใกล้ user มากกว่า latency saving จะมาก.
Early Hints ต่างจาก preload tag ใน HTML อย่างไร
คำถามที่ผมเจอบ่อยมากคือ "ถ้า preload ใน <head> อยู่แล้ว ทำไมยังต้องใช้ Early Hints". คำตอบสั้น ๆ คือ preload ใน HTML ทำงานหลัง HTML parser เห็น tag ซึ่งต้องรอ HTML byte ตัวแรกถึงเบราว์เซอร์ก่อน. Early Hints ทำงาน ก่อน HTML ตัวแรกจะถึง browser ด้วยซ้ำ. ตารางเปรียบเทียบ:
คุณสมบัติ HTTP 103 Early Hints <link rel="preload"> ใน HTML
เวลาที่ทำงาน ก่อน HTML response ใด ๆ หลัง browser parse <head>
ความซับซ้อนการตั้งค่า ต้องคอนฟิก server/CDN เพิ่ม tag ใน HTML
ช่วยลด TTFB-gap ใช่ ลดได้สูงสุด ไม่ได้ รอ HTML
เบราว์เซอร์ที่รองรับ Chromium-based ทุกเบราว์เซอร์ modern
ใช้กับ Server-Side Rendering ช้า ๆ เหมาะมาก ช่วยจำกัด
ปลอดภัยเมื่อ resource ไม่ถูกใช้ เสีย bandwidth เบา เสีย bandwidth เบา
คำตอบที่ถูกต้องคือ ใช้คู่กัน . Early Hints ลดเวลา preload-start, แต่ tag preload ใน HTML ยังจำเป็นเป็น fallback สำหรับ Firefox/Safari และเป็น single source of truth สำหรับทีมที่ดูแล HTML.
วัดผลกระทบจริงด้วย DevTools และ RUM
วัดผลคือส่วนที่คนข้ามบ่อย. ผมยืนยันว่าทุก optimization ต้องมีการวัดก่อน-หลัง. วิธีของผม:
1) DevTools Network panel
ใน Chrome DevTools 120+ คอลัมน์ Initiator จะแสดง "early-hints" สำหรับทรัพยากรที่ถูก preload ผ่าน 103 และ Waterfall จะแสดง 103 เป็น row เล็ก ๆ สีเทาก่อน 200 OK. ถ้าไม่เห็น 103 แสดงว่า server/CDN ยังไม่ส่ง.
2) PerformanceResourceTiming API
// รันใน console เพื่อตรวจว่า resource ไหนถูก preload ผ่าน Early Hints
performance.getEntriesByType('resource')
.filter(r => r.initiatorType === 'early-hints')
.forEach(r => console.log(r.name, r.responseEnd - r.requestStart, 'ms'));
3) RUM ด้วย web-vitals.js
ส่ง LCP ก่อนเปิด Early Hints ลง analytics ของคุณ (CrUX, Datadog, SpeedCurve) เปรียบเทียบ p75 LCP หลังจาก rollout. ถ้าไม่เห็น delta อย่างน้อย 100 ms บนหน้า dynamic แสดงว่า origin TTFB ของคุณอาจจะเร็วเกินกว่าที่จะได้ประโยชน์.
Warning: อย่าวัดผลเฉพาะใน lab (WebPageTest, Lighthouse) อย่างเดียว เพราะ throttling profile ทำให้ network slowdown ดูเอื้อกับ Early Hints มากเกินจริง. วัดด้วย RUM เสมอเพื่อยืนยันบน real user network.
ข้อผิดพลาดที่ผมเจอบ่อย
หลายปีที่ผมช่วย client ติดตั้ง Early Hints มีหลุมห้าหลุมที่เจอซ้ำ (ผมก็เคยตกเองทั้งห้าตอน roll out รอบแรก):
Preload URL ผิด . บางคนใส่ /css/main.css?v=1 ใน 103 แต่ HTML อ้าง /css/main.css?v=2 เบราว์เซอร์ดาวน์โหลดทั้งคู่ เปลือง bandwidth เปล่า ๆ. ใช้ build hash จาก server-side template เสมอ.
ลืม crossorigin attribute ในการ preload font หรือ resource จาก CDN ที่ต้อง CORS. Browser จะ download ซ้ำเพราะ second request ขอ CORS.
ส่ง hint มากเกินไป . ผมเคยเห็น 18 preload links ใน 103 บนเพจ blog เดียว ผลคือ browser แย่ง bandwidth กับ HTML ตัวหลัก LCP แย่ลง 80 ms. กฎผม: 3–5 critical resources เท่านั้น.
Cache 103 ที่ CDN ตอน origin เปลี่ยน asset hash . ระบบ build ใหม่ ๆ hash เปลี่ยน แต่ Cloudflare ยัง cache hint เก่า 7 วัน. วิธีแก้คือ purge cache หลัง deploy หรือใช้ Cache-Control: no-store บน 103 ผ่าน Worker.
เปิดบนหน้า static cached . Page ที่ TTFB อยู่ที่ 30 ms (เพราะ cached ที่ edge แล้ว) จะไม่ได้ประโยชน์เลย ยังเสีย complexity. ตรวจ TTFB ก่อนตัดสินใจเปิด.
ถ้าอยากเสริมเทคนิคโหลดเร็วต่อ ลองดู Speculation Rules API คู่มือ Prerender และ Prefetch ซึ่งทำงานในชั้นถัดไปจาก Early Hints. Early Hints เร่ง first navigation, Speculation Rules เร่ง navigation ครั้งต่อ ๆ ไป.
เมื่อไหร่ที่ควรเปิด Early Hints
กฎง่าย ๆ ของผมหลังจาก roll out บนไซต์ประมาณ 40 ตัว: เปิด Early Hints บนหน้าที่มี TTFB > 400 ms เท่านั้น และมี critical render-blocking resource อย่างน้อย 1 ตัว (CSS, font, hero image). สำหรับหน้า static ที่ cached แล้วเปิดไม่ได้ผล. สำหรับ SPA ที่ HTML แทบไม่มีอะไร (ทุกอย่างมาจาก JS) ก็ไม่ค่อยช่วย เพราะ critical resource ตัวจริงถูก discover หลัง JS execute เสร็จแล้ว.
อนาคตของ Early Hints และ HTTP 1xx ใหม่
ในปี 2026 มี draft อยู่ใน IETF httpbis สำหรับ HTTP/3 with Extensible Priorities ที่จะให้ Early Hints แนบ priority hint ได้ด้วย รวมถึง draft "Resource Hints over HTTP" ที่จะให้ส่ง Compute-Pressure และ Save-Data negotiation กลับใน 103. ผมจะติดตามตรงนี้ใกล้ ๆ น่าจะ stable ในช่วงต้น 2027.
คำถามที่พบบ่อย
HTTP 103 Early Hints ปลอดภัยกับเบราว์เซอร์ที่ไม่รองรับหรือไม่?
ปลอดภัยครับ. HTTP spec กำหนดให้ 1xx informational response สามารถถูก ignore ได้โดยปลอดภัย. Firefox และ Safari จะข้าม 103 ไปเหมือนไม่ได้รับ ไม่มีผลกระทบเชิงลบใด ๆ ดังนั้นเปิดได้เลยโดยไม่ต้อง user-agent sniff.
Early Hints ช่วย LCP จริงหรือเปล่า?
ช่วยจริงครับ. บนหน้าที่ TTFB > 500 ms ผมเห็น LCP ลด 200–450 ms อย่างสม่ำเสมอ. Shopify รายงาน p75 LCP ดีขึ้น 32% หลัง roll out ทั้งระบบ. แต่บนหน้า static ที่ cached แล้ว benefit อาจน้อยมากเพราะ TTFB-gap แทบไม่มี.
ต่างจาก HTTP/2 Server Push อย่างไร?
Server Push ถูก deprecated ใน Chrome 106 (2022) เพราะ "push" ทรัพยากรที่ browser อาจมีใน cache อยู่แล้ว เปลือง bandwidth. Early Hints แก้ปัญหานี้ด้วยการให้ browser ตัดสินใจเอง, server แค่ "บอกใบ้" ว่าควร preload อะไร browser จะ skip ถ้ามี cache อยู่.
ต้องใช้ HTTP/2 หรือ HTTP/3 หรือไม่?
แนะนำให้ใช้ HTTP/2 ขึ้นไปครับ. บน HTTP/1.1 เกิด head-of-line blocking ทำให้ 103 อาจบล็อก 200 OK ในบาง implementation. Cloudflare และ Fastly จะ skip การส่ง 103 อัตโนมัติเมื่อ connection เป็น HTTP/1.1 เพื่อความปลอดภัย.
ส่ง Early Hints ได้ทรัพยากรกี่รายการก่อนจะเปลืองเกินไป?
กฎของผมคือ 3–5 critical resources เท่านั้น. Browser มี HTTP/2 stream limit (default 100) และมี bandwidth budget ที่ต้องแบ่งกับ HTML ตัวจริง preload เกิน 5 ตัวมักทำให้ LCP แย่ลงเพราะแย่ง bandwidth กับ image และ HTML.