灏天阁

带你深入理解 CSR,SSR,SSG 等常用渲染模式

· Yin灏

前言

近期的工作涉及到了CSR, SSR, SSG,这篇文章旨在总结和归纳这些渲染模式。

SPAMPASSRCSR 这几个词可能在你的工作生涯中经常出现,网上相关文章也很多。如果你对这些概念感到模糊或完全不了解,希望本文能帮助你理解这些渲染模式。

SPA 与 MPA

MPA

MPA(multiple page application) 称为多页应用, 指的是有多个页面的应用,从技术手段上来讲,你可以这么粗略地理解。

  • 首屏速度快:各个页面相互独立,需要单独维护多个 html 页面,每个请求都直接返回 html。

  • 切换页面比较慢:基于原生浏览器的文档跳转(navigating across documents)。因此每一次的页面更新都是一次页面重载,这将带来巨大的重启性能消耗。

  • 对 SEO 友好:页面在初始时,就具有全部的页面内容而非 「无状态」,从而达到更好的收录效果。

image.png

SPA

SPA(single page application)称为单页应用。通过 js 去感知到 url 的变化,动态的将当前页面的内容清除掉,然后将下一个页面的内容挂载到当前页面上。此时的路由不是后端来做了,而是前端来做,动态显示需要的组件。

  • 页面切换速度快:路由跳转是基于特定的实现(如 vue-router,react-router 等前端路由),而非原生浏览器的文档跳转,避免了不必要的整个页面重载。

  • 前后端分离:基于前端路由,SPA 与应用后端解耦,使得前端不再依赖于后端的路由分配。

  • 首屏时间慢:首屏除了 html 还要额外请求并执行 js 文件,通过 js 在空页面上渲染首屏。

  • SEO 不友好:内容都是靠 js 渲染生成出来的,但搜索引擎并不识别这部分内容,导致 SEO 效果差

image (1).png

CSR(Client Side Rendering)

CSR(客户端渲染)是一种在浏览器上执行 JavaScript 以生成 DOM 并显示内容的渲染方法。CSR 更贴近现代前端开发,我们通常使用的 Vue 和 React 默认使用 CSR。其大致流程如下:

  1. 浏览器向前端服务器请求 html 和 js

  2. html 页面为空,初始加载不显示任何内容,通过执行 js 渲染内容

  3. 通过后端暴露的 API 进行交互

对于典型的 CSR 应用程序,浏览器仅接收一个用作应用程序容器的 HTML 页面,因此也称为单页应用,所以 CSR 的特点与之前提到的 SPA 类似。

image (2).png

SSR(Server Side Rendering)

概念

在早期,开发者喜欢使用 JSP 或其他模板渲染引擎来构建应用,这种方法被称为 SSR(服务器端渲染)。与客户端渲染不同,SSR 输出的是渲染完整的 HTML,整个渲染过程在服务器端进行。

用户发起请求后,SSR 的流程大致如下:

  1. 后端服务通过数据层进行查询用户所需内容

  2. 处理业务逻辑

  3. 使用模板拼接页面

  4. 将渲染好的 HTML 字符串返回给客户端

  5. 前端渲染并加载 JS 脚本完成剩余交互

image (3).png

早期的 SSR 在内容更新/跳转,都需要再次请求服务器,重新加载一次页面。但在 React, Vue 等框架的加持下,我们语境中的 SSR 一般指的是首屏服务端渲染同构渲染(Isomorphic render,即新开页面访问 SSR 应用时,首屏会返回完整的 html,浏览器通过注水hydrate)成为 React 或 Vue 应用,后续用户进行跳转等操作时不会再向服务端请求 html,而是以类似单页应用的方式进行。

ssr1 (1).png

同构直出

上文中,我们提到了hydrate这个词,正是通过该操作使静态 html 页面转换成一个 Vue 或 React 应用,这依赖于 React 和 Vue 提供的「同构直出」功能。

在服务端渲染中,有两种页面渲染的方式:

  • 后端服务器获取数据并组装 HTML 返回给浏览器解析渲染页面

  • 浏览器在交互过程中,请求新的数据并动态更新渲染页面

这两种渲染方式的不同点在于运行环境的不同。同一份代码可以在客户端和服务器端运行,两个环境的渲染结果应该保持一致。因此,我们需要实现客户端和服务器端的路由、页面模板和数据共享。

image (4).png

我们通过webpack将打包出两份代码,一份在服务端运行。

vue服务端渲染构建 (1).png

整体流程

以 Nuxt 为例,整体的渲染流程如下所示:

SSR (1).png

两个重要的概念

脱水(dehydrate)

将组件树序列化成静态的 HTML 片段,能直接看到初始视图,不过已经无法与之交互了,但这种便携的形态尤其适合网络传输。这个脱去动态数据,成为风干标本一样的静态快照的过程被称为脱水(dehydrate)。

注水(hydrate)

与脱水相反,将这个 html 躯干复活为 Vue 应用的过程称为注水。客户端并不重新生成 HTML 组件,而是重用服务器发送给它的 HTML,并附加「数据」与「交互性」,构建成完整的 Vue 应用,这个过程被称为注水(hydrate)。

Hydration is a process where a frontend framework like React, VueJS re-uses the static HTML structure it receives from the server (that was created at server-side at build time), and instead of re-generating the HTML nodes on the browser, simply “breathes” event handlers and interactivity into it.

SSR 与 CSR 的对比

优点

  • SEO 友好:搜索引擎爬虫可以直接抓取到最终页面内容。而 CSR 直接返回的 html 为空壳,对一些不加载执行 js 的低级爬虫来说这个页面的内容就是空的。

  • 首屏时间更短:服务端渲染直接返回带有数据的 HTML 文本,浏览器只需解析 HTML 并构建 DOM 树,无需额外执行 JS 来渲染首屏元素。

缺点

  • 占用服务器资源:渲染工作从浏览器转移到服务器,新增了数据获取的 IO 和渲染 HTML 的 CPU 占用。

  • 代码复杂度增加:需要同时兼容客户端和服务器端,代码编写时需要考虑两端的执行环境,且某些依赖库只能在客户端运行,增加了编码的复杂性。

SSG(Static Site Generation)

概念

SSG(静态站点生成)与 SSR 的原理非常类似,但不同之处在于 HTML 文件是预先生成的,而不是在服务器实时生成。

工作流程

  1. 构建阶段:在构建过程中,SSG 将源文件和模板(如 HTML、CSS)结合,生成静态页面。这些页面通常由预定义的布局、组件和样式组成。

  2. 预渲染:SSG 在构建过程中会自动执行预渲染。这意味着 SSG 会根据预定义的路由和数据源,在构建时生成静态页面的多个实例。例如,对于一个博客,每篇文章都可以在构建过程中生成一个独立的静态页面。

  3. 静态输出:一旦构建完成,SSG 将生成的静态页面输出到目标文件夹中。这些页面包含所有必要的 HTML、CSS 和 JavaScript,以及任何相关的静态资源(如图像、视频等)。

  4. 部署:生成的静态页面可以直接部署到任何支持静态文件的 Web 服务器上。因为这些页面不需要动态生成,所以它们可以被高效地缓存和交付给访问者,提供更好的性能和可扩展性。

  5. 用户访问:首屏直接解析 html 生成 dom。接着和 SSR 一样通过 hydrate 将整个应用转变成为 React 或 Vue 应用,使用户在交互时与单页应用无异。

ssg图示 (1).jpeg

特点

SSG 的优缺点都非常明显,通常适用于静态页面,例如文档、博客、帮助站点和电子商务产品。

优点

  • 性能高:相比 SSR 减轻了服务器压力,还可以将生成的静态资源放到 CDN 上,充分利用缓存。

  • SEO 友好:搜索引擎爬虫可以直接抓取到最终页面内容

  • 易于部署:生成的静态页面可以直接部署到任何支持静态文件的 Web 服务器上,无需依赖 Node 环境等。

  • 高度安全性:由于服务器不需要运行程序,因此服务器漏洞仅限于操作系统本身,维护也更加方便。

缺点

  • 静态:只适用于静态数据,对于经常改动的数据,需要每次重新生成页面。

ISR(Incremental Static Regeneration)

概念

ISR(增量式网站渲染)结合了 SSG 和 SSR 的优势。ISR 的核心思想是将部分静态页面在构建时生成,并在用户访问时进行增量更新。

在 ISR 中,静态页面的构建仍然是在构建时完成的,类似于 SSG。然而,与完全静态的 SSG 不同,ISR 允许某些页面在构建后仍保持动态,并在用户首次访问时进行渲染。一旦渲染完成,生成的静态页面被缓存,并在后续的请求中被直接提供,以提高性能和响应速度。

工作流程

  1. 构建阶段:在构建过程中,使用 SSG(静态站点生成器)生成静态页面,并将这些页面上传到 CDN。

  2. 用户发起页面请求:

    • 请求静态页面: CDN 直接返回;
    • 请求 ISR 页面,且该页面未被 CDN 缓存:直接响应 fallback 页面,浏览器接收到该页面后以 CSR 的形式渲染出内容;同时 CDN 会将请求转发到服务端,触发服务端渲染,服务器动态地生成页面内容,并返回给 CDN 进行缓存
    • 请求 ISR 页面,该页面 CDN 已有缓存且未过期:直接返回缓存的 html 页面
    • 请求 ISR 页面,该页面 CDN 已有缓存但已经过期:直接返回这份过期的缓存给浏览器,此时用户看到的是缓存已经过期的页面;同时 CDN 会将请求转发到服务端,触发服务端渲染,服务器动态地生成页面内容,并返回给 CDN 将该页面的缓存更新

ISR (1).png

特点

优点

ISR 的优势在于它在静态和动态之间找到了一个平衡点。对于不经常变动的内容,可以通过 SSG 生成完全静态的页面,从而实现快速加载和低服务器负载。而对于可能需要频繁更新的部分,如评论区或实时数据,ISR 可以使用 SSR 来动态生成这些内容,并在后续的请求中进行增量更新,从而保持页面的实时性。

缺点

  • 访问到没被预渲染过的次要内容触发 fallback,需要进行 CSR,加载较慢。

  • 访问到之前被预渲染过,但已经过期且未更新的页面,会得到过期的缓存响应。用户刷新一次,才能看到新的数据。

应用场景

本质上来说,ISR 仍然是 SSG 的范畴,复杂场景仍然无法应对。其典型应用场景包括博客评论、最新文章列表等。通过将这些动态内容与静态页面结合使用,可以在保持高性能和安全性的同时,提供更丰富和实时的用户体验。

- Book Lists -