beizhu
type
Post
status
Published
date
May 23, 2023
slug
summary
服务器端渲染是在服务器端将数据和模板结合起来生成HTML页面,然后将完整的HTML页面返回给浏览器,浏览器不需要再等待JavaScript代码执行,可以更快地渲染页面。SSR可以提高网站性能,改善用户体验,还可以提高SEO的友好程度
tags
React
Next.js
JS
category
技术
icon
password
SSR过程
当用户首次访问您的应用站点时,服务器会对请求进行处理,并根据相应的 URL 在服务端根据对应路径渲染对应的 HTML 模版。
- 此时,HTML模板是具有页面真正内容的,但是并不包含任何交互逻辑,因为它是一个完全静态的站点。
- 然后,服务器会下发这份包含静态内容的 HTML 模版,和对应的JavaScript脚本,首先呈现给用户的是一个静态的HTML页面,因此首屏渲染速度会非常快,因为不需要在客户端下载和执行 JavaScript 脚本,并且对于SEO也非常友好,因为搜索引擎的爬虫可以很容易地找到其中的关键字匹配。
- 接下来,浏览器会下载当前 HTML 的 JS 脚本,用来添加交互逻辑。
- 最后,当完整下载完 HTML 中的 JS 脚本后,页面会被(hydrate),从而为静态HTML元素再次添加对应的事件处理,使得页面具有交互性,由此渲染整个页面。
在hydration过程完成后,您的客户端框架会接管后续的渲染过程。这意味着,针对导航链接的跳转和页面渲染,您无需再从服务器请求,而是可以利用客户端的路由(History Api/Hash Api)和JS进行页面渲染,从而实现快速、即时的页面交互。
hydration
上述过程中有一个非常重要的关键字 hydration(水合)。
首次访问页面时,页面的静态 HTML 是在服务端生成的。 在服务端我们将生成的静态 HTML 以及 HTML 中携带的 JS 脚本发送到客户端。
此时静态 HTML 会立即显示在用户视野中,然后浏览器会利用网络进程下载当前 HTML 脚本中的 JS 脚本。
当 JS 脚本下载完成后,会立即执行同时发生一种被称为 hydration 的过程。
所谓的 hydration 简单来说,也就是客户端下载完成 JS 脚本后,浏览器会执行下载的 JS 脚本这些脚本中有部分内容会将已经存在的 HTML 内容通过执行下载的 JS 脚本添加上对应的事件监听器 从而保证页面的交互。
注意,在 React、Vue 中 hydration 并不意味这重新渲染。因为在 Server 端已经渲染了和 Client 完全相同的 DOM 结构所以完全没有必要在此重新渲染。
所以 hydration 的过程是给当前页面中已经生成的 HTML 页面添加上对应的事件监听器。
这也是为什么在 Next 等框架中为什么必须要保证 Server 端和 Client 的渲染 HTML 结构必须一致的原因。
比如以 Next 举例来说:
- 当用户访问 www.baidu.com 时,服务端接收到请求调用 ReactDOMServer.renderToString() 生成当前页面的 HTML 静态结构。
- 服务器会下发这个 HTML 页面给客户端,同时这个 HTML 页面上也会携带一部分 JS 脚本 script 标签。
- 用户的浏览器中会立即展现到该 HTML 页面,同时也会下载对应 JS 脚本并执行。
- 当 JS 脚本执行完毕后,客户端会调用 ReactDOM.hydrate() 发生水合为当前页面的 HTML 页面添加事件交互处理,同时后续由 JS 接管页面的跳转渲染。

针对于第一步 Next 中存在 Automatic Static Optimization 的优化,并不一定会在每次访问时调用 renderToString 方法,有可能在构建时也会直接生成对应的 HTML 模版。
当然,在最新的 Next v13中已经支持了Stream以及 Server Components。

RSC、SSR、SSG的区别
SSG是后端「编译时方案」。使用SSG的业务,后端代码在编译时会生成HTML(通常会被上传CDN)。当前端发起请求后,后端(或CDN)始终会返回编译生成的HTML。对应我们next.js中的
getStaticPropsRSC与SSR则都是后端「运行时方案」。也就是说,他们都是前端发起请求后,后端对请求的实时响应。根据请求参数不同,可以作出不同响应。
同为后端运行时方案,RSC与SSR的区别主要体现在输出产物:
- 类似于SSG,SSR的输出产物是HTML,浏览器可以直接解析。
- RSC会流式输出一种「类JSON」的数据结构,由前端的React相关插件解析。
既然输出产物不同,那么他们的应用场景也是不同的。
比如,在需要考虑SEO(即需要后端直接输出HTML)时,SSR与SSG可以胜任(都是输出HTML),而RSC则不行(流式输出)。
同时,由于实现不同,同一个应用中可以同时存在SSG、SSR以及RSC。
SSR优势
- 更好的SEO: 搜索引擎爬取的是HTML的内容,如果站点使用客户端渲染,由于是异步加载数据,由于爬虫无法等待异步请求完成,爬虫无法获取到页面完整的HTML内容,因此不利于SEO优化。而服务器端渲染是直接获取到HTML内容的,对SEO更为友好。
- 更快的首屏渲染,因为相较于 SPA 它少了在 Client 中下载和执行 JS 脚本后渲染的过程。
- 页面不需要 JS 也可以正常渲染,虽然没有 JS 意味着页面失去了可交互性。但对于禁用 JS 的用户来说,展示一些静态内容总比 SPA 应用的白屏来的更加友好一些对吧。
- 更高的安全性: 服务器端渲染不会暴露应用的业务逻辑和敏感代码到客户端,因此提供了更高的安全性。
服务器端渲染在某些情况下会带来更好的用户体验和更高的安全性。然而,与客户端渲染相比,服务器端渲染需要更多的服务器资源,并且需要更多的工作来配置和维护。因此,需要根据实际情况来选择是否使用服务器端渲染。
SSR劣势
当然,任何技术方案在不同场景下也存在它自己的不足。
- 强依赖于服务。
针对于 CSR 的方式它是一种纯静态资源。我们可以直接将它放在 CDN 上就可以良好的用户访问到,而 SSR 的方式必须依赖于一个服务器进行服务端预渲染。(当然纯 SSG 应用我们不在这个讨论范围之内)
同时,有服务的地方就存在并发压力。当你需要为你的应用考虑服务端渲染的方式时,一定不要忘记为你的服务器进行压测。
- Time to Interactive 可交互时间 (TTI) 的增长,虽然说 SSR 的方式有效的缩短了首屏加载的方式,但是会增加所谓的TTI(可交互时间)。
所谓的 TTI 指标测量页面从开始加载到主要子资源完成渲染,并能够快速、可靠地响应用户输入所需的时间。
因为 SSR 的方式在用户访问时会下发当前页面中静态的 HTML 内容,也就是所谓的 First Contentful Paint 首次内容绘制 (FCP) 会非常快速,但是页面需要用户交互效果缺又需要下载和执行完成 JS 脚本发生 hydatrion 后才具有交互性。
这也就造成页面的 TTI 相较于 CSR 方式会有所差劲,因为 CSR 在渲染完成后就会立即具有交互性(不需要其他任何多余步骤)。

当然业内存在非常多基于 SSR 的优秀框架,比如 Next、Remix、Nuxt 等等。
号称世界上第一个 O(1) 的 JavaScript SSR 框架:qwik。有空可以了解下