[{"data":1,"prerenderedAt":741},["ShallowReactive",2],{"navigation":3,"\u002Farticles\u002Fssr":34,"\u002Farticles\u002Fssr-surround":738},[4],{"title":5,"path":6,"stem":7,"children":8,"page":33},"Articles","\u002Farticles","articles",[9,13,17,21,25,29],{"title":10,"path":11,"stem":12},"用 Daily Snapshot 提升統計查詢速度","\u002Farticles\u002Fdaily-snapshot","articles\u002Fdaily-snapshot",{"title":14,"path":15,"stem":16},"GKE 部署","\u002Farticles\u002Fgke-deployment","articles\u002Fgke-deployment",{"title":18,"path":19,"stem":20},"從 LLM 到 Agent：打通底層邏輯","\u002Farticles\u002Fllm-to-agent","articles\u002Fllm-to-agent",{"title":22,"path":23,"stem":24},"資訊安全實踐","\u002Farticles\u002Fsecurity-best-practices","articles\u002Fsecurity-best-practices",{"title":26,"path":27,"stem":28},"單機架構的性能優化","\u002Farticles\u002Fsingle-machine-performance","articles\u002Fsingle-machine-performance",{"title":30,"path":31,"stem":32},"伺服器渲染 SSR","\u002Farticles\u002Fssr","articles\u002Fssr",false,{"id":35,"title":30,"author":36,"body":40,"date":730,"description":731,"extension":732,"externalUrl":733,"image":734,"meta":735,"minRead":372,"navigation":384,"path":31,"seo":736,"stem":32,"__hash__":737},"blog\u002Farticles\u002Fssr.md",{"name":37,"avatar":38},"Gary",{"src":39,"alt":37},"\u002Fimages\u002Fselfie.webp",{"type":41,"value":42,"toc":714},"minimark",[43,48,61,64,67,144,146,149,160,162,165,187,189,192,220,222,225,449,451,454,459,466,470,477,481,484,486,489,500,502,505,570,572,576,701,710],[44,45,47],"h2",{"id":46},"什麼是-ssr","什麼是 SSR？",[49,50,51,52,56,57,60],"p",{},"SSR 即",[53,54,55],"strong",{},"伺服器端渲染（Server-Side Rendering）","，指網頁的 HTML 在",[53,58,59],{},"伺服器","上產生完整內容後，再傳送給瀏覽器顯示。",[62,63],"hr",{},[44,65,66],{"id":66},"渲染方式比較",[68,69,70,86],"table",{},[71,72,73],"thead",{},[74,75,76,80,83],"tr",{},[77,78,79],"th",{},"項目",[77,81,82],{},"SSR",[77,84,85],{},"CSR（Client-Side Rendering）",[87,88,89,100,111,122,133],"tbody",{},[74,90,91,95,97],{},[92,93,94],"td",{},"HTML 生成位置",[92,96,59],{},[92,98,99],{},"瀏覽器",[74,101,102,105,108],{},[92,103,104],{},"首屏速度",[92,106,107],{},"快",[92,109,110],{},"慢（需等 JS 執行）",[74,112,113,116,119],{},[92,114,115],{},"SEO",[92,117,118],{},"友好",[92,120,121],{},"不友好（爬蟲難以讀取）",[74,123,124,127,130],{},[92,125,126],{},"伺服器負擔",[92,128,129],{},"較重",[92,131,132],{},"較輕",[74,134,135,138,141],{},[92,136,137],{},"互動性",[92,139,140],{},"較低（需搭配 Hydration）",[92,142,143],{},"高",[62,145],{},[44,147,148],{"id":148},"運作流程",[150,151,156],"pre",{"className":152,"code":154,"language":155},[153],"language-text","使用者請求頁面\n      ↓\n伺服器執行程式碼，取得資料\n      ↓\n伺服器產生完整 HTML\n      ↓\n回傳 HTML 給瀏覽器\n      ↓\n瀏覽器顯示頁面（可立即看到內容）\n      ↓\nJavaScript 載入，進行 Hydration（賦予互動能力）\n","text",[157,158,154],"code",{"__ignoreMap":159},"",[62,161],{},[44,163,164],{"id":164},"優點",[166,167,168,175,181],"ul",{},[169,170,171,174],"li",{},[53,172,173],{},"首屏載入快","：用戶更快看到內容，體驗好",[169,176,177,180],{},[53,178,179],{},"SEO 友好","：搜尋引擎爬蟲可直接讀取完整 HTML",[169,182,183,186],{},[53,184,185],{},"社群分享預覽正常","：Open Graph 標籤可被正確解析",[62,188],{},[44,190,191],{"id":191},"缺點",[166,193,194,200,206],{},[169,195,196,199],{},[53,197,198],{},"伺服器負擔重","：每次請求都需伺服器運算",[169,201,202,205],{},[53,203,204],{},"TTFB 較慢","（Time To First Byte）：伺服器需先處理完才回傳",[169,207,208,211,212,215,216,219],{},[53,209,210],{},"開發複雜度高","：需注意程式碼在伺服器與瀏覽器環境的差異（如 ",[157,213,214],{},"window","、",[157,217,218],{},"document"," 不存在於伺服器端）",[62,221],{},[44,223,224],{"id":224},"開發需注意",[166,226,227],{},[169,228,229,232,233,236,237,240,243,244,246,247,250,251,262],{},[53,230,231],{},"儲存 Token 的環境差異","：",[157,234,235],{},"localStorage"," 只存在於瀏覽器，伺服器端無法存取。",[238,239],"br",{},[53,241,242],{},"解法：改用 Cookie 存 token","\nCookie 會隨每個 HTTP request 自動帶到伺服器，server 和 client 都能讀取。",[238,245],{},"Nuxt 提供內建的 ",[157,248,249],{},"useCookie","，統一處理兩端差異：",[166,252,253,256],{},[169,254,255],{},"Server：從 request header 讀取 cookie，寫入放進 response header",[169,257,258,259],{},"Client：直接讀寫 ",[157,260,261],{},"document.cookie",[150,263,267],{"className":264,"code":265,"language":266,"meta":159,"style":159},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const token = useCookie('token', {\n  maxAge: 60 * 60 * 24, \u002F\u002F 1 天\n  httpOnly: true,        \u002F\u002F 防 XSS\n  secure: true,          \u002F\u002F 只走 HTTPS\n})\n\ntoken.value = 'abc123' \u002F\u002F 寫入\nconsole.log(token.value) \u002F\u002F 讀取\ntoken.value = null       \u002F\u002F 清除\n","ts",[157,268,269,308,338,355,370,379,386,410,432],{"__ignoreMap":159},[270,271,274,278,282,286,290,293,296,300,302,305],"span",{"class":272,"line":273},"line",1,[270,275,277],{"class":276},"spNyl","const",[270,279,281],{"class":280},"sTEyZ"," token ",[270,283,285],{"class":284},"sMK4o","=",[270,287,289],{"class":288},"s2Zo4"," useCookie",[270,291,292],{"class":280},"(",[270,294,295],{"class":284},"'",[270,297,299],{"class":298},"sfazB","token",[270,301,295],{"class":284},[270,303,304],{"class":284},",",[270,306,307],{"class":284}," {\n",[270,309,311,315,318,322,325,327,329,332,334],{"class":272,"line":310},2,[270,312,314],{"class":313},"swJcz","  maxAge",[270,316,317],{"class":284},":",[270,319,321],{"class":320},"sbssI"," 60",[270,323,324],{"class":284}," *",[270,326,321],{"class":320},[270,328,324],{"class":284},[270,330,331],{"class":320}," 24",[270,333,304],{"class":284},[270,335,337],{"class":336},"sHwdD"," \u002F\u002F 1 天\n",[270,339,341,344,346,350,352],{"class":272,"line":340},3,[270,342,343],{"class":313},"  httpOnly",[270,345,317],{"class":284},[270,347,349],{"class":348},"sfNiH"," true",[270,351,304],{"class":284},[270,353,354],{"class":336},"        \u002F\u002F 防 XSS\n",[270,356,358,361,363,365,367],{"class":272,"line":357},4,[270,359,360],{"class":313},"  secure",[270,362,317],{"class":284},[270,364,349],{"class":348},[270,366,304],{"class":284},[270,368,369],{"class":336},"          \u002F\u002F 只走 HTTPS\n",[270,371,373,376],{"class":272,"line":372},5,[270,374,375],{"class":284},"}",[270,377,378],{"class":280},")\n",[270,380,382],{"class":272,"line":381},6,[270,383,385],{"emptyLinePlaceholder":384},true,"\n",[270,387,389,391,394,397,399,402,405,407],{"class":272,"line":388},7,[270,390,299],{"class":280},[270,392,393],{"class":284},".",[270,395,396],{"class":280},"value ",[270,398,285],{"class":284},[270,400,401],{"class":284}," '",[270,403,404],{"class":298},"abc123",[270,406,295],{"class":284},[270,408,409],{"class":336}," \u002F\u002F 寫入\n",[270,411,413,416,418,421,424,426,429],{"class":272,"line":412},8,[270,414,415],{"class":280},"console",[270,417,393],{"class":284},[270,419,420],{"class":288},"log",[270,422,423],{"class":280},"(token",[270,425,393],{"class":284},[270,427,428],{"class":280},"value) ",[270,430,431],{"class":336},"\u002F\u002F 讀取\n",[270,433,435,437,439,441,443,446],{"class":272,"line":434},9,[270,436,299],{"class":280},[270,438,393],{"class":284},[270,440,396],{"class":280},[270,442,285],{"class":284},[270,444,445],{"class":284}," null",[270,447,448],{"class":336},"       \u002F\u002F 清除\n",[62,450],{},[44,452,453],{"id":453},"相關概念",[455,456,458],"h3",{"id":457},"hydration","Hydration",[49,460,461,462,465],{},"SSR 傳回靜態 HTML 後，瀏覽器的 JavaScript 接管並賦予互動能力的過程，稱為 ",[53,463,464],{},"Hydration（水合）","。",[455,467,469],{"id":468},"ssgstatic-site-generation","SSG（Static Site Generation）",[49,471,472,473,476],{},"在",[53,474,475],{},"建置時","預先產生 HTML，而非每次請求時才產生。適合內容不常變動的頁面。",[455,478,480],{"id":479},"isrincremental-static-regeneration","ISR（Incremental Static Regeneration）",[49,482,483],{},"Next.js 提供的功能，結合 SSG 與 SSR，可設定頁面定期重新產生。",[62,485],{},[44,487,488],{"id":488},"適用場景",[166,490,491,494,497],{},[169,492,493],{},"需要 SEO 的網站（部落格、電商、新聞）",[169,495,496],{},"首屏效能要求高的頁面",[169,498,499],{},"內容依賴使用者身份或即時資料的頁面",[62,501],{},[44,503,504],{"id":504},"常用框架",[68,506,507,520],{},[71,508,509],{},[74,510,511,514,517],{},[77,512,513],{},"框架",[77,515,516],{},"基於",[77,518,519],{},"語言",[87,521,522,535,547,559],{},[74,523,524,529,532],{},[92,525,526],{},[53,527,528],{},"Nuxt.js",[92,530,531],{},"Vue",[92,533,534],{},"JavaScript \u002F TypeScript",[74,536,537,542,545],{},[92,538,539],{},[53,540,541],{},"SvelteKit",[92,543,544],{},"Svelte",[92,546,534],{},[74,548,549,554,557],{},[92,550,551],{},[53,552,553],{},"Next.js",[92,555,556],{},"React",[92,558,534],{},[74,560,561,566,568],{},[92,562,563],{},[53,564,565],{},"Remix",[92,567,556],{},[92,569,534],{},[62,571],{},[44,573,575],{"id":574},"程式碼範例nuxtjs","程式碼範例（Nuxt.js）",[150,577,581],{"className":578,"code":579,"language":580,"meta":159,"style":159},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003C!-- pages\u002Findex.vue -->\n\n\u003Cscript setup lang=\"ts\">\nconst { data } = await useFetch('https:\u002F\u002Fapi.example.com\u002Fdata')\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv>{{ data.title }}\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n","vue",[157,582,583,588,592,618,651,660,664,673,693],{"__ignoreMap":159},[270,584,585],{"class":272,"line":273},[270,586,587],{"class":336},"\u003C!-- pages\u002Findex.vue -->\n",[270,589,590],{"class":272,"line":310},[270,591,385],{"emptyLinePlaceholder":384},[270,593,594,597,600,603,606,608,611,613,615],{"class":272,"line":340},[270,595,596],{"class":284},"\u003C",[270,598,599],{"class":313},"script",[270,601,602],{"class":276}," setup",[270,604,605],{"class":276}," lang",[270,607,285],{"class":284},[270,609,610],{"class":284},"\"",[270,612,266],{"class":298},[270,614,610],{"class":284},[270,616,617],{"class":284},">\n",[270,619,620,622,625,628,630,633,637,640,642,644,647,649],{"class":272,"line":357},[270,621,277],{"class":276},[270,623,624],{"class":284}," {",[270,626,627],{"class":280}," data ",[270,629,375],{"class":284},[270,631,632],{"class":284}," =",[270,634,636],{"class":635},"s7zQu"," await",[270,638,639],{"class":288}," useFetch",[270,641,292],{"class":280},[270,643,295],{"class":284},[270,645,646],{"class":298},"https:\u002F\u002Fapi.example.com\u002Fdata",[270,648,295],{"class":284},[270,650,378],{"class":280},[270,652,653,656,658],{"class":272,"line":372},[270,654,655],{"class":284},"\u003C\u002F",[270,657,599],{"class":313},[270,659,617],{"class":284},[270,661,662],{"class":272,"line":381},[270,663,385],{"emptyLinePlaceholder":384},[270,665,666,668,671],{"class":272,"line":388},[270,667,596],{"class":284},[270,669,670],{"class":313},"template",[270,672,617],{"class":284},[270,674,675,678,681,684,687,689,691],{"class":272,"line":412},[270,676,677],{"class":284},"  \u003C",[270,679,680],{"class":313},"div",[270,682,683],{"class":284},">",[270,685,686],{"class":280},"{{ data.title }}",[270,688,655],{"class":284},[270,690,680],{"class":313},[270,692,617],{"class":284},[270,694,695,697,699],{"class":272,"line":434},[270,696,655],{"class":284},[270,698,670],{"class":313},[270,700,617],{"class":284},[702,703,704],"blockquote",{},[49,705,706,709],{},[157,707,708],{},"useFetch"," 在 SSR 模式下會於伺服器端執行，取得資料後渲染完整 HTML 再回傳給瀏覽器；切換頁面時則在客戶端執行。",[711,712,713],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}",{"title":159,"searchDepth":310,"depth":310,"links":715},[716,717,718,719,720,721,722,727,728,729],{"id":46,"depth":310,"text":47},{"id":66,"depth":310,"text":66},{"id":148,"depth":310,"text":148},{"id":164,"depth":310,"text":164},{"id":191,"depth":310,"text":191},{"id":224,"depth":310,"text":224},{"id":453,"depth":310,"text":453,"children":723},[724,725,726],{"id":457,"depth":340,"text":458},{"id":468,"depth":340,"text":469},{"id":479,"depth":340,"text":480},{"id":488,"depth":310,"text":488},{"id":504,"depth":310,"text":504},{"id":574,"depth":310,"text":575},"2025-08-02","介紹伺服器端渲染的運作原理、與 CSR 的差異、優缺點，以及在 Nuxt.js 開發中需要注意的事項。","md",null,"\u002Fimages\u002Fssr.jpg",{},{"title":30,"description":731},"hw4A-FXUQKCuF4DmsKU8bH8c8xlfqReYj9Uq6rQgsQc",[739,733],{"title":26,"path":27,"stem":28,"description":740,"children":-1},"拆解單機系統的優化路線，以及用回應時間與吞吐量來衡量系統性能。",1781661891804]