iT邦幫忙

2025 iThome 鐵人賽

DAY 3
0
Modern Web

從 React 學 Next.js:不只要會用,還要真的懂系列 第 3

【Day 3】CSR vs SSR:瀏覽器渲染到伺服器渲染

  • 分享至 

  • xImage
  •  

昨天已經先了解了 React 和 Next.js 的關係和差異後,接著我們再進入一個深入認識 Next.js 之前需要先了解的渲染模式的部分。今天先來看看我們平常最常會聽到的 CSR 和 SSR。
(前提說明:這篇是之前在自己的部落格有分享過的主題,所以內容會跟之前的文章內容差不多)

什麼是 CSR ?

從字面上來看,CSR 指的就是「客戶端渲染(Client-Side Rendering)」,這裡的「客戶端」指的就是使用者的瀏覽器。也就是說,在 CSR 的模式下,HTML 並不是在伺服器產生後直接送給使用者,而是在瀏覽器中透過 JavaScript 動態產生並插入 HTML,最終將畫面渲染出來。

如果想判斷一個網站是否採用了 CSR,可以透過「檢視原始碼」的方式來觀察。
若在檢視時,如果發現 body 裡只有一個空的 div 標籤和一個 script 標籤(如下圖所示),而沒有實際內容,就代表這個 HTML 是個骨架,並沒有被伺服器預先填入資料。也就是說,最後畫面上呈現的內容,是在 JavaScript 執行之後,才在瀏覽器端動態插入進來的。
https://ithelp.ithome.com.tw/upload/images/20250815/20130914m5AUXejYvm.png

這樣的渲染模式也正是「客戶端渲染」這個名稱的由來:頁面的資料和畫面,並不是伺服器一開始就準備好的,而是透過 JavaScript 在使用者的裝置上進行組裝與顯示的。

CSR 和 SPA 的關係是?

說到 CSR,大家會想到的應該還有 SPA,那這兩者的關係究竟是什麼呢?其實 CSR 並不等於 SPA,因為 CSR 是一種渲染模式,而 SPA 則是一種應用程式的類型,也就是所謂的「單頁式應用程式 (Single-page application)」,其他像是 MPA、PWA 都是一種應用程式類型。

而 CSR 和 SPA 之間的關係則是 「CSR 這個渲染模式,是實現 SPA 的常見方式」,也就是說這兩者彼此的確有關係,但並不等價。

CSR 運作方式

大致上了解什麼是 CSR 後,接著來看看 CSR 的運作方式吧!

如果要用一句話說明,CSR 渲染出畫面的整個流程的話,就會是:

「下載並執行從伺服器 response 回來的 HTML 檔案內引用的 javaScript 檔案,在瀏覽器產生完整的 HTML,以呈現完正的頁面」。

從完整的流程來看的話,則是:

「輸入網址進入網頁 → 對伺服器發送 reques → 伺服器透過 response 把包含基礎內容的 HTML 檔案(只含有掛載完整內容的 <div> 元素)和打包好的 JavaScript、CSS 等靜態資源 發送回來 → 瀏覽器下載並執行 JavaScript → JavaScript 在客戶端動態生成並渲染完整的 HTML 和頁面內容 → 用戶看到完整的網頁」 。

看到這裡,你可能會有一個疑問,「response 回來的 HTML、CSS、JavaScript 是從哪產生的?」,我們可以再回到我們進行開發時的流程下去思考。當我們開發完成後,將網站部署出去前,一定會做的動作就是跑 build 的指令,通常會是 npm run build。當我們執行 build 的指令後,其實可以觀察到會產出類似以下的這些的檔案。
https://ithelp.ithome.com.tw/upload/images/20250815/20130914tvyZdGwRu4.png

這些檔案也就是我們在瀏覽器上輸入網址後,從伺服器 response 拿到的打包後的檔案,完整的 HTML 內容則是會等到下載並執行裡面的 JavaScript 檔案後,才會被渲染出來。

什麼是 SSR ?

前面已經了解到什麼是 CSR了,接著來看看與 CSR 只有一字之差的 SSR 是什麼吧!一樣從字面上來看的話,所謂的 SSR 也就是「伺服器端渲染 (Server-Side Rendering)」。換句話說,也就是說 SSR 有別於 CSR 會直接從伺服器的 response 拿到在伺服器上渲染完成的完整的 HTML,所以當嘗試用檢視網頁原始碼來查看原始的 HTML 時,就可以看到和頁面呈現內容一樣完整的 HTML。
例如以下這張圖,可以看到實際肉眼看到的內容,出現在網頁原始碼裡面。

https://ithelp.ithome.com.tw/upload/images/20250815/20130914Wrg14HDFlL.png

看到這裡有些人可能會突然跑出一個想法,那就是「JavaScript 跑去哪了?」。大家應該都有聽說過,想要讓一個網頁可以達到互動的效果,一定會需要 JavaScript,但是整個靜態的 HTML 都是伺服器幫我們產生,那 JavaScript 會在哪個階段出現呢?這個就不得不提到新舊時代 SSR 的差異。

舊時代與新時代的 SSR

就如同前面所提到的內容一樣,伺服器會幫我們產出一個完整的靜態 HTML 檔案,所以畫面呈現的部分一定是沒有問題的,但是當我們需要互動時(例如送出表單),一般的靜態的網站並沒辦法做到,那究竟是要怎麼達到這樣的效果呢?這裡就出現了新舊時代 SSR 的差異。

在「舊時代的 SSR 模式」中,如果想要進行送出表單之類的互動操作,會需要伺服器的幫忙,也就是說當我們送出表單時,也會向伺服器發送 request,進行相對應的處理,並且再次 response 一個新的完整 HTML,所以在做互動的動作時,整個網頁會被刷新,如果從 Dev Tools 觀察的話,就可以發現到當我們進行輸入表單的動作或是切換頁面,都會看到有 response 回來一個完整新的 HTML,如同以下的畫面。

https://i.imgur.com/XbDzW78.gif

與舊時代的 SSR 模式不同的是在「新時代的 SSR 模式」中,SSR 模式不只可以處理靜態頁面,也可以優雅地處理互動操作,因為在新時代的 SSR 模式中,會有一個 hydration 的動作,也就是將 JavaScript 綁定在 DOM 元素上,這就能讓 SSR 不用在做互動的操作時都要請伺服器處理,切換頁面時,也不需要重新向伺服器取得新的 HTML。從這樣的改變來看,其實不難發現到所謂的新時代的 SSR,就是一種結合 CSR 的混合渲染模式。

當我們觀察新時代的 SSR 網站也就可以發現雖然網頁原始碼一樣有顯示當前頁面的完整 HTML,但是當進行切換頁面或提交表單等的動作,並不會再重新取得全新的 HTML,也就會像是以下這個狀況一樣:
https://i.imgur.com/NrlmYym.gif

SSR 怎麼運作

知道 SSR 有著舊時代和新時代的差異後,緊接著來看看 SSR 的運作方式究竟是什麼。

簡單來說就是:
「對伺服器發送 request,取得完整的 HTML 顯示在頁面上」。

如果分成舊時代和新時代來看完整的流程的話,則會像是以下這樣:
舊時代的 SSR:
「輸入網址進入網頁 → 對伺服器發送 reques → 伺服器產生完整的 HTML 檔案 → 透過 response 把完整的 HTML 檔案和 CSS 等靜態資源發送回來(在 HTML 檔案中可能會包含處理特效的少量 JavaScript) → 用戶看到完整的網頁」 。

新時代的 SSR:
「輸入網址進入網頁 → 對伺服器發送 request → 伺服器產生完整的 HTML 檔案 → 透過 response 把完整的 HTML 檔案和 CSS 等靜態資源發送回來 → 瀏覽器下載 HTML 中用 script 引用的 JavaScript → 將 event Handlers 綁定到 DOM 上(Hydrate) → Hydrate 完成後,使用者就可以和頁面互動」。

從上面新舊時代的 SSR 的運作流程來看的話,就可以發現從舊時代轉換到新時代的差異,在舊時代的 SSR 模式中,單純就是讓伺服器產生一個靜態的檔案來呈現畫面,如果要做一些互動操作,就必須還要透過伺服器進行處理,所以也就會需要伺服器再回傳一個新的 HTML 檔案;而在新時代的 SSR 模式中,除了讓伺服器產生靜態檔案來呈現畫面外,還會透過 JavaScript 讓頁面可以在瀏覽器中進行操作,這裡也就是 Hydration 的部分,所以只有在第一次進入畫面時,會透過伺服器回傳一個完整的 HTML 檔案,之後切換頁面就不需要再讓伺服器提供完整的 HTML 檔案了。
而我們常常會聽到的 Next.js 和 Nuxt.js 就是新時代 SSR 模式的框架。

這裡我們再稍微深入一點看看在 Next.js 框架中 build 的時候會出現什麼檔案:

https://ithelp.ithome.com.tw/upload/images/20250815/20130914jf4iRGkzsm.png

從這張圖片可以發現到在 SSR 模式的框架下 build 出來的檔案會比 CSR 來得複雜很多,這是因為在 SSR 模式下,不是單純使用 JavaScript 來產生完整的 HTML 內容,而是需要透過伺服器渲染,而且渲染出完整 HTML 的這個伺服器也並不是靜態伺服器(例如:Nginx),這個伺服器其實是由框架所建構的 node server,也就是說 build 出來的檔案,除了 CSS 等的靜態檔案外,還有關於伺服器渲染的邏輯及伺服器的設定內容。

從部署看 CSR 及 SSR 的差異

接著再讓我們更進一步地去從部署流程來思考 CSR 和 SSR 之間的差異。
當我們部署 CSR 專案的時候,我們就只是很單純把 build 出來的靜態檔案放到伺服器(例如:Nginx)上,當瀏覽器對伺服器發送 request 時,就是把對應的檔案 response 回去,接下來就和前面所提到過的一樣,會去下載並執行 HTML 中 script 所引用的 JavaScript 檔案,接著在瀏覽器渲染出完整的 HTML。

而部署 SSR 的專案時,就不是單純的把靜態資源放到伺服器中,而是需要透過 Next.js 或 Nuxt.js 提供的指令,將 node server 給建立起來,因為產生出完整 HTML 的伺服器是 node server,即使是部署到 Nginx 中,也不是由 Nginx 來產生完整的 HTML,還是會需要透過 Nginx 將 request 轉送給 node server,才能產生出完整的 HTML 來回應給伺服器。

CSR 和 SSR 的優點和缺點

最後再來回顧一下前面說提到的 CSR 及 SSR 的特點,也總結一下它們各自的優缺點!

CSR 由於伺服器回傳的 HTML 是一個不含完整內容的 HTML ,需要在瀏覽器中透過下載並執行 javaScript 檔案,才會產生完整的畫面,所以第一次進入頁面的時候,會需要等待一些時間,才會看到完整的畫面,也就是說第一次進入畫面時,會看到白色的畫面一下子,才會出現完整的畫面,但是在之後,不論是對畫面進行操作或是切換頁面,都不需要再對伺服器發送 request,所以切換頁面和進行操作時,整體呈現會比較流暢。

SSR 由於是在伺服器中產生完整的 HTML 給瀏覽器呈現,所以首次進入頁面,不會顯示白色的畫面,但是在舊時代的 SSR 模式中,因為沒 JavaScript 的幫助,所以每次進行操作或是切換頁面時,都要重新和伺服器請求一個新的 HTML,整體的操作過程也就比較不流暢,因為會有刷新頁面的過程;但在新時代的 SSR 模式中,則是因為有 JavaScript 的幫助 (也就是前面所提到的 Hydration),使得在首次拿到完整的 HTML 之後,接著在操作及切換頁面的動作中,就可以透過 JavaScript 讓整體流程更順暢,不用一定要藉由伺服器的幫助才能進行,也就是說新時代的 SSR 結合了 SSR 和 CSR 的優點,但也因為新時代的 SSR 讓伺服器不只是「產生 HTML」,而是「執行一整個 React 應用來產生畫面」,也就讓伺服器負荷與舊時代的 SSR 相比來得高,但這也換來了更彈性、更強大的前後端整合能力。

最後也整理了一個對照表給大家參考
https://ithelp.ithome.com.tw/upload/images/20250815/201309140gWD4wMYHf.png

今天 CSR 和 SSR 認識的部分就先到這裡,明天再繼續 SSG 和 ISR 的部分。


上一篇
【Day 2】什麼是 Next.js?與 React 有何不同?
下一篇
【Day 4】SSG vs ISR:從純靜態頁面到可自動更新的靜態頁面
系列文
從 React 學 Next.js:不只要會用,還要真的懂11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言