ํ—ค๋” Streaming SSR (RSC + Suspense) ๊ธฐ์กด SSR ์„ค๋ช…
Content-Type text/x-component text/html; charset=utf-8 RSC ์ „์šฉ MIME ํƒ€์ž…. React๊ฐ€ ํด๋ผ์ด์–ธํŠธ์—์„œ ์ด๊ฑธ ํ•ด์„ํ•ด์„œ ์ปดํฌ๋„ŒํŠธ๋กœ hydration ํ•จ. ๊ธฐ์กด SSR์€ ์ผ๋ฐ˜ HTML ์‘๋‹ต
Transfer-Encoding chunked (์—†์Œ) or ์ž๋™ ์„ค์ • ์‘๋‹ต์„ chunk ๋‹จ์œ„๋กœ ์ŠคํŠธ๋ฆฌ๋ฐ ์ „์†กํ•จ. HTML ์ „์ฒด๊ฐ€ ์•„๋‹Œ, ์ผ๋ถ€๋งŒ ๋จผ์ € ๋ณด๋‚ด๊ณ  ๋‚˜๋จธ์ง€๋Š” ์ˆœ์ฐจ์ ์œผ๋กœ
Connection keep-alive close ๋˜๋Š” ์ƒ๋žต ์ŠคํŠธ๋ฆฌ๋ฐ ๋™์•ˆ ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•ด์•ผ ํ•˜๋ฏ€๋กœ, keep-alive๋กœ ๋ช…์‹œ. ๊ธฐ์กด SSR์€ ์‘๋‹ต ๋๋‚˜๋ฉด ๋ฐ”๋กœ ๋Š์Œ
Keep-Alive timeout=5 ์—†์Œ ์„œ๋ฒ„๊ฐ€ ์ปค๋„ฅ์…˜์„ ์ตœ๋Œ€ 5์ดˆ๊ฐ„ ์œ ์ง€ํ•˜๋ฉด์„œ chunk ์ „์†กํ•  ์ˆ˜ ์žˆ์Œ. Chunk๊ฐ€ ์—†์œผ๋ฉด timeout ํ›„ ์ข…๋ฃŒ
Cache-Control no-store, must-revalidate public, max-age=0, s-maxage=0, must-revalidate ๋“ฑ Streaming SSR์€ ์บ์‹œ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋ช…์‹œ์ ์œผ๋กœ no-store. ๊ธฐ์กด SSR๋„ no-cache์ผ ์ˆ˜ ์žˆ์œผ๋‚˜, ์ผ๋ถ€ ISR์€ ์บ์‹ฑ ํ—ˆ์šฉ
Content-Encoding gzip gzip or ์—†์Œ ์‘๋‹ต์ด gzip์œผ๋กœ ์••์ถ•๋จ. Streaming์—์„œ๋„ ์••์ถ•๋œ chunk๊ฐ€ ์ˆœ์ฐจ์ ์œผ๋กœ ์ „๋‹ฌ๋จ
Vary RSC, Next-Router-State-Tree, ... ๋ณดํ†ต Accept-Encoding, Cookie ๋“ฑ Vercel CDN์ด๋‚˜ ํด๋ผ์ด์–ธํŠธ๊ฐ€ RSC ์ƒํƒœ, ๋ผ์šฐํ„ฐ ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ์‘๋‹ต์„ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํžŒํŠธ ์ œ๊ณต
rsc (Request ํ—ค๋”) 1 ์—†์Œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ React Server Component๋ฅผ ์š”์ฒญํ•œ๋‹ค๋Š” ํ”Œ๋ž˜๊ทธ. Next.js๊ฐ€ ์ด๊ฑธ ๋ณด๊ณ  RSC ์‘๋‹ต ์ƒ์„ฑ
next-router-state-tree ์กด์žฌ ์—†์Œ ํด๋ผ์ด์–ธํŠธ ๋ผ์šฐํ„ฐ ์ƒํƒœ ํŠธ๋ฆฌ๋ฅผ ์„œ๋ฒ„์— ์ „๋‹ฌํ•ด์„œ ์ •ํ™•ํ•œ ๊ฒฝ๋กœ ๋งคํ•‘, prefetch ๋Œ€์‘
Accept */* ๋™์ผ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์–ด๋–ค ํƒ€์ž…์˜ ์‘๋‹ต๋„ ํ—ˆ์šฉ
Accept-Encoding gzip, deflate, br, zstd ๋™์ผ ์–ด๋–ค ์••์ถ• ํฌ๋งท์„ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ˆ˜์šฉ ๊ฐ€๋Šฅํ•œ์ง€ ์ „๋‹ฌ
Content-Length ์—†์Œ (chunked์ด๋ฏ€๋กœ) ์žˆ์Œ (์™„๋ฃŒ๋œ HTML์˜ ์ด ํฌ๊ธฐ) Streaming์€ ์ด ๊ธธ์ด๋ฅผ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋žต๋˜๊ณ , ๋Œ€์‹  chunked ์ „์†ก ์‚ฌ์šฉ

๐Ÿ” ์ฃผ์š” ํ•ต์‹ฌ ์ฐจ์ด ์š”์•ฝ

ํ—ค๋” ์—ญํ•  Streaming SSR ๊ธฐ์กด SSR
MIME ํƒ€์ž… text/x-component โ†’ RSC text/html
์ „์†ก ๋ฐฉ์‹ chunked โ†’ flush() ์ŠคํŠธ๋ฆฌ๋ฐ ์ „์ฒด ์‘๋‹ต ์™„๋ฃŒ ํ›„ ์ „์†ก
์—ฐ๊ฒฐ ์ƒํƒœ keep-alive โ†’ ์—ฐ๊ฒฐ ์œ ์ง€ ์‘๋‹ต ํ›„ close
์‘๋‹ต ๊ธธ์ด ๋ฏธ์ • (Content-Length ์—†์Œ) ๊ณ ์ • ๊ธธ์ด ์žˆ์Œ
์บ์‹œ ์ •์ฑ… no-store, must-revalidate ํ•„์š”์— ๋”ฐ๋ผ ์บ์‹œ ํ—ˆ์šฉ ๊ฐ€๋Šฅ
CDN ๋Œ€์‘ Vary: RSC, ๋ผ์šฐํ„ฐ ์ƒํƒœ โ†’ ์‘๋‹ต ๋‹ค์–‘ํ™” ๋‹จ์ˆœ Accept-Encoding, Cookie ๋“ฑ

๐Ÿ’ก ์ฐธ๊ณ : Vary ํ—ค๋”์˜ ์—ญํ• 

Streaming SSR์—์„œ ์‘๋‹ต์— ๋”ฐ๋ผ ์ด๋ ‡๊ฒŒ ๋“ค์–ด๊ฐ:

โžก๏ธ ์ด๋Š” "RSC ์—ฌ๋ถ€", "๋ผ์šฐํ„ฐ ์ƒํƒœ", "์••์ถ• ์—ฌ๋ถ€"์— ๋”ฐ๋ผ ์„œ๋ฒ„๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ HTML chunk ์กฐํ•ฉ์„ ์ „์†กํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ช…์‹œํ•จ

โžก๏ธ CDN ์บ์‹ฑ์—์„œ ์ž˜๋ชป๋œ ์‘๋‹ต ๊ณต์œ ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Œ


๐ŸŽฏ ๊ฒฐ๋ก  ์š”์•ฝ

Streaming SSR์€ HTTP ๋ ˆ๋ฒจ์—์„œ๋„ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•จ

ํŠนํžˆ text/x-component, chunked, rsc: 1, Vary ๋“ฑ์€ ๊ธฐ์กด SSR์—๋Š” ์—†๋Š” Streaming ํŠนํ™” ํ—ค๋”๋“ค์ด๊ณ ,

์ด๋ฅผ ํ†ตํ•ด ๋ธŒ๋ผ์šฐ์ €์™€ Next.js๊ฐ€ HTML์ด ์•„๋‹Œ "์ปดํฌ๋„ŒํŠธ ์กฐ๊ฐ"์„ ์ฃผ๊ณ ๋ฐ›๋Š” ๊ตฌ์กฐ๋ฅผ ์™„์„ฑํ•จ