当前位置: 首页> 文旅> 文化 > 服务端渲染 SSR 原理和实现

服务端渲染 SSR 原理和实现

时间:2025/8/29 23:52:37来源:https://blog.csdn.net/weixin_43294560/article/details/139650853 浏览次数:0次

文章目录

  • CSR 优缺点
  • SSR
  • Server + Client 同构
  • Hydrate 水合(客户端激活)
  • 数据的获取和初始化
  • 预加载资源
  • 避免应用单例
  • 避免全局副作用代码

CSR 优缺点

优点

  • 整个网站打包进 JavaScript 里,当 JavaScript 下载完毕后,相当于网站的页面资源都被下载好了。这样在跳转新页面的时候,不需要向服务器再次请求资源( JavaScript 会直接操作 DOM 进行页面渲染),从而让整个网站的使用体验上更加流畅

缺点

  • 在 JavaScript 体积较大的情况下,会有白屏问题
  • 因为会先下载一个空的 HTML,然后才通过 JavaScript 进行渲染,这个空的 HTML 会导致某些搜索引擎无法通过爬虫正确获取网站信息,从而影响网站的搜索引擎排名

SSR

优点

  • HTML 在服务器端就已经渲染好了,浏览器拿到就可以渲染,减少白屏时间
  • 服务器端渲染拥有良好的首屏性能和 SEO

缺点

  • 每次跳转页面都要向服务器重新请求,意味着用户每次切换页面都要等待一小段时间
  • SSR 相比 CSR 会占用较多的服务器端资源
// 以 vue 为例
import { renderToString } from 'vue/server-renderer'
import { createSSRApp } from 'vue'// 一个计数的 vue 组件
function createApp() {// 通过 createSSRApp 创建一个vue实例return createSSRApp({data: () => ({ count: 1 }),template: `<button @click="count++">{{ count }}</button>`,});
}const app = createApp();// 通过 renderToString 将 vue 实例渲染成字符串
renderToString(app).then((html) => {// 将字符串插入到 html 模板中const htmlStr = `<!DOCTYPE html><html><head><title>Vue SSR Example</title></head><body><div id="app">${html}</div></body></html>`;console.log(htmlStr);
});

Server + Client 同构

  • 开始的步骤和 SSR 相同,将生成的 HTML 字符串返回给客户端,同时将 CSR 需要的 JavaScript 也一并发送给客户端
  • 客户端在接收到 SSR 生成的 HTML 后,页面还会再执行一次 CSR 的流程
  • 客户端只有请求的第一个页面是在服务器端渲染的,其它页面则都是在客户端进行的
  • 这样就同时兼顾首屏、SEO和用户体验的网站
    在这里插入图片描述

Hydrate 水合(客户端激活)

  • 服务器执行应用的初始渲染,生成静态 HTML,并将其发送给客户端,这一步其实发送的是静态的模版( Dehydrate 脱水)
  • 客户端加载额外的 JavaScript 代码,并在已有的静态 HTML 上绑定事件监听器等,使页面变得可交互
  • SSR 的瓶颈也就取决于 Hydrate 的过程

数据的获取和初始化

  • 挂载到 window 上或者 Vuex、Pinia 等其它方案
const htmlStr = `<!DOCTYPE html><html><head>...// 将数据格式化成json字符串,放到script标签中<script>window.__INITIAL_DATA__ = ${JSON.stringify(initData)}</script></head>...</html>
`;

组件中获取数据

function createApp() {return createSSRApp({data: () => ({ count: 1 }),template: `<button @click="count++">{{ count }}</button>`,// 自定义一个名为 asyncData 的函数asyncData: async () => { // 在处理远程数据并 return 出去const data = await getSomeData()return data; },async mounted() {// 如果已经有数据了,直接从 window 中获取if (window.__INITIAL_DATA__) {// 有服务端数据时,使用服务端渲染时的数据this.count = window.__INITIAL_DATA__;window.__INITIAL_DATA__ = undefined;return;} else {// 如果没有数据,就请求数据this.count = await getSomeData();}}});
}

预加载资源

  • 在打包过程中生成 manifest
    • 作用是将打包后的模块 ID 与它们关联的 Chunk 和资源文件进行映射
  • 依靠这个 manifest 获取资源的路径,然后创建 Link 标签拼接到 HTML 模板中即可

避免应用单例

  • 服务器端返回给客户端的每个请求都应该是全新的、独立的应用程序实例,避免直接将对象或变量创建在全局作用域,否则它将在所有请求之间共享,在不同请求之间造成状态污染

避免全局副作用代码

  • 比如 vue 服务器端渲染只会执行 beforeCreate 和 created 生命周期,应该避免在这两个生命周期里产生全局副作用的代码
  • 例如使用 setInterval 设置定时器。在纯客户端的代码中,我们可以设置一个定时器,然后在 beforeDestroy 或 destroyed 生命周期中将其销毁。但是在 SSR 期间并不会调用销毁钩子函数,所以定时器将永远保留下来,最终造成服务器内存溢出
关键字:服务端渲染 SSR 原理和实现

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: