前端服务端渲染 SSR

什么是SSR?它解决了什么问题?怎么做SSR?⭐️⭐️ 实操

SSR(Server-Side Rendering,服务端渲染 )是一种 将Html内容在服务器端生成并返回给客户端 的技术,与传统的客户端渲染(CSR)相比,它能显著 优化首屏加载速度SEO(搜索引擎优化)

一、核心概念:什么是 SSR?

客户端渲染(CSR) 中,浏览器从服务器获取的是几乎空白的 HTML仅包含 <div id="app"></div> 等容器 ),然后通过加载 JavaScript 脚本,在客户端动态生成 DOM 并渲染页面(典型如 Vue、React 单页应用)。

首屏渲染 :SPA(Single Page Application)将页面渲染放到客户端执行,并且在渲染之前要加载大量的Javascript代码,所以首屏渲染需要花费较长时间。而SSR直接在服务端渲染完再返回客户端,使用户能够快速看到页面内容。

SSR 则是在 服务器端 提前将 Vue、React 等框架的组件渲染成完整的 HTML 字符串,包含页面的所有内容 ,然后将这个完整的 HTML 直接返回给浏览器 。浏览器收到后无需等待 JavaScript 加载完成即可展示页面,后续再通过客户端脚本 "激活"(hydrate)页面,使其具备交互能力。

二、工作流程:SSR 如何运作?

以 Vue/React 框架的 SSR 为例,核心流程如下:

  1. 客户端发起请求 :用户访问某个 URL(如 https://example.com/page)。
  2. 服务器接收请求:Node.js 服务器(如 Express、Koa)接收请求,解析路由。
  3. 数据预获取:服务器根据路由,提前请求所需数据(如接口调用、数据库查询)。
  4. 组件渲染 :将数据注入到 Vue/React 组件中,在服务器端通过框架的 SSR 引擎(如 vue-server-rendererReactDOMServer将组件渲染为完整的 HTML 字符串
  5. 返回完整 HTML :服务器将渲染好的 HTML 字符串(包含 <html><head><body> 及所有内容)返回给客户端。
  6. 客户端 "激活" :浏览器展示 HTML 内容(首屏快速可见),同时加载客户端 JavaScript 脚本,脚本执行后 "激活" 页面(绑定事件、初始化状态),使页面从静态变为可交互的动态页面。

三、SSR 与 CSR 的关键区别

特性 客户端渲染(CSR) 服务端渲染(SSR)
首屏加载速度 慢(需加载 JS 后动态渲染 快(直接返回完整 HTML,浏览器可立即解析
SEO 友好性 差(搜索引擎可能,无法解析动态生成的内容 好(搜索引擎可直接抓取完整 HTML 内容
服务器压力 小(仅提供静态资源和接口) 大(需处理渲染和数据请求,需更高性能服务器

四、SSR 的优势

  1. 优化首屏加载速度 :客户端无需等待 JavaScript 下载、解析和执行,直接展示服务器返回的完整 HTML ,尤其对网络条件差或设备性能弱的用户更友好。用户能更快看到页面内容,减少 "白屏时间",降低跳出率
  2. 提升 SEO 效果 :搜索引擎爬虫更易抓取服务器返回的静态 HTML 内容(传统 CSR 中,爬虫可能只看到空白容器,导致页面内容无法被索引)。

五、SSR 的劣势

  1. 增加服务器负载 :服务器需要处理渲染逻辑和数据请求,相比仅提供静态资源的 CSR 服务器,CPU 和内存消耗更高,需要更强的服务器性能或负载均衡策略。

  2. 开发复杂度提高

    • 代码需兼容: "服务端渲染 " 和 "客户端激活" 两个环境
    • 需处理数据同步问题:(服务端预获取的数据需传递给客户端,避免客户端重新请求)。
    • 构建和部署流程更复杂(需 Node.js 服务器环境,无法直接部署到纯静态文件服务器)。
  3. 部分浏览器 API 限制 :服务端渲染时无法访问浏览器特有的 API(如 windowlocalStorage),需在客户端激活后使用。

六、适用场景

  • 对首屏加载速度和 SEO 要求高的网站 (如电商首页、博客、新闻网站)。

不适合的场景:

  • 后台管理系统,用户对首屏速度不敏感,SEO 无关紧要。

七、实现方式:如何落地 SSR?

1. 基于框架的原生方案
  • Vue 2/3 :使用官方的 vue-server-renderer(Vue 2 )或 @vue/server-renderer(Vue 3),配合 Node.js 服务器(如 Express)实现。
  • React :使用 ReactDOMServer 进行服务端渲染,ReactDOM.hydrate 进行客户端激活,常见搭配 Next.js 框架简化开发。
2. 成熟的 SSR 框架(降低开发成本)
  • Next.js(React 生态):最流行的 SSR 框架之一,内置 SSR、静态生成(SSG)、增量静态再生(ISR)等功能,简化路由、数据预获取等逻辑。
  • Nuxt.js (Vue 生态):类似 Next.js,为 Vue 提供 SSR 解决方案,支持自动路由、数据预获取(asyncDatafetch 方法)等。
  • SvelteKit(Svelte 生态):支持 SSR 和静态生成,以轻量高效为特点。
3. 核心实现要点(以 Vue + Express 为例)
  • 服务端配置 :通过 vue-server-renderer 创建渲染器(createRenderer),将组件渲染为 HTML。
  • 数据预获取 :在服务端路由中提前获取数据(如 asyncData 方法),并注入到组件的 context 中。
  • 客户端激活 :客户端引入同一份组件代码,通过 hydrate 方法激活页面,复用服务端渲染的 DOM。
  • 避免浏览器 API :服务端渲染时,需通过 process.env.VUE_ENV 区分环境,避免在服务端调用 window 等 API。

总结

SSR 通过服务端提前渲染 HTML 解决了 CSR 的首屏速度和 SEO 问题,但其代价是更高的服务器负载和开发复杂度。实际开发中,需根据业务需求(如 SEO 重要性、首屏速度要求)选择是否使用,或结合 SSG、CSR 混合使用(如 Next.js 的 "混合渲染" 模式)。对于 React/Vue 开发者,推荐直接使用 Next.js/Nuxt.js 等成熟框架,降低 SSR 落地难度。

Vue 服务端渲染框架(SSR)

Nuxt.js 和 vue-server-renderer 均服务于 Vue 生态的服务端渲染(SSR),核心关系是 "Nuxt.js 基于 vue-server-renderer 封装,是更高层的框架"。

vue-server-renderer 是 Vue 官方提供的底层工具库,核心功能是将 Vue 实例(组件树)渲染为 HTML 字符串,是 Vue 实现 SSR 的 "基石"。

Nuxt.js 作为 Vue 生态的 SSR 框架,本质是对 vue-server-renderer 的封装 :它在底层调用 vue-server-renderercreateBundleRenderer 等 API 完成服务端渲染的核心逻辑(将 Vue 组件转换为 HTML),但在此之上增加了大量工程化能力(如自动路由、数据预取、构建配置等),简化了开发者的使用成本。

  • 选择建议

    • 若需高度定制 SSR 逻辑(如复杂的缓存策略、中间层架构 ),用 vue-server-renderer 手动搭建;
    • 若追求开发效率,快速实现 Vue SSR/SSG 应用,优先用 Nuxt.js。

以下是使用 Vue 实现 SSR 的基本步骤:

  1. 安装相关依赖:确保你的项目中已经安装了 Vue、Vue Router、Vue Server Renderer 等依赖。

  2. 创建服务器入口文件 :创建一个服务器入口文件,如 server.js。在文件中引入必要的模块,包括 Vue、Vue Server Renderer、Express(或其他后端框架)等。

  3. 编写服务器端渲染逻辑

    • 创建一个 Vue 实例,配置路由、数据等。
    • 使用 Vue Server Renderer 的 createRenderer 方法创建一个 renderer 实例。
    • 在路由处理器中调用 renderer 实例的 renderToString 方法来将 Vue 实例渲染为字符串。
  4. 处理静态资源:在服务器端渲染时,需要处理静态资源的加载和引用。可以使用 Webpack 进行服务器端渲染的配置,以处理静态资源的导出和加载。

  5. 客户端激活 :在服务器端渲染后,需要在客户端激活 Vue 实例,以便能够响应交互事件和更新页面。可以在 HTML 中插入一个 JavaScript 脚本,并在脚本中使用 createApp 方法来创建客户端应用程序实例。

在 Vue2项目中 Nuxt.js 框架实现SSR

在 Vue2 项目中用 Nuxt.js 实现 SSR 非常简单,因为 Nuxt.js 2 本身就是基于 Vue2 设计的 SSR 框架,能直接复用 Vue2 的语法和组件。以下是针对已有 Vue2 项目的改造步骤(如果是新项目,直接按步骤 1 创建即可),核心逻辑是 "用 Nuxt2 的约定式配置替代 Vue2 的手动配置"。

一、如果是新建项目(最简单,推荐)

直接创建基于 Vue2 的 Nuxt2 项目,自带 SSR 能力:

1. 创建 Nuxt2 项目(确保基于 Vue2)
bash 复制代码
# 安装 Nuxt2 脚手架
npm install -g create-nuxt-app

# 创建项目(命名为 vue2-nuxt-ssr)
create-nuxt-app vue2-nuxt-ssr

关键配置选择(其他默认):

  • Choose Vue version → 选 2.x(绑定 Vue2);
  • Choose rendering mode → 选 Universal (SSR / SSG)(开启 SSR);
2. 写一个 SSR 页面(用 Vue2 语法)

Nuxt2 会自动将 pages 目录下的 .vue 文件转为路由,在 pages/index.vue 中写页面(完全兼容 Vue2 选项式 API):

html 复制代码
<!-- pages/index.vue -->
<template>
  <div>
    <h1>Vue2 + Nuxt2 SSR 示例</h1>
    <!-- 服务端渲染的动态数据 -->
    <p>服务端生成时间:{{ serverTime }}</p>
    <p>服务端随机数:{{ randomNum }}</p>
  </div>
</template>

<script>
// 完全遵循 Vue2 选项式 API
export default {
  // asyncData:Nuxt2 服务端数据预取方法(Vue2 项目中核心)
  // 作用:在服务端渲染前执行,返回的数据直接注入页面 HTML
  asyncData() {
    return {
      // 服务端获取当前时间(服务端无 window,直接用 Date)
      serverTime: new Date().toLocaleString(),
      // 服务端生成随机数(每次刷新由服务端重新计算)
      randomNum: Math.random().toFixed(4)
    }
  }
}
</script>
3. 运行并验证 SSR 生效
bash 复制代码
cd vue2-nuxt-ssr
npm run dev  # 启动服务(默认 http://localhost:3000)

验证 SSR :访问页面后,右键 → "查看页面源代码",如果能在源码中直接看到 服务端生成时间:xxx服务端随机数:xxx(而非空标签),说明 SSR 成功(服务端已将数据渲染到 HTML 中)。

二、如果是改造已有 Vue2 项目(核心步骤)

如果已有一个 Vue2 项目(如 Vue-CLI 创建),只需 3 步改造为 Nuxt2 SSR 项目:

1. 安装 Nuxt2 依赖
js 复制代码
# 进入现有 Vue2 项目
cd your-vue2-project

# 安装 Nuxt2 核心依赖(依赖 Vue2)
npm install nuxt@2.x --save
2. 调整目录结构(按 Nuxt 约定)

Nuxt2 用约定式目录替代手动配置,需添加 / 修改:

plaintext 复制代码
your-vue2-project/
├── pages/           # 新增:路由页面(Nuxt 自动生成路由)
│   └── index.vue    # 首页(内容同上一步的 index.vue)
├── package.json     # 修改启动脚本
└── nuxt.config.js   # 新增:Nuxt 配置文件(极简版)
  • nuxt.config.js(极简配置):

    javascript 复制代码
    module.exports = {
      mode: 'universal'  // 关键:开启 SSR 模式
    }
  • package.json(添加启动脚本):

    json 复制代码
    "scripts": {
      "dev": "nuxt dev"  // 启动 Nuxt 开发服务
    }
3. 迁移核心代码
  • 将原 Vue2 项目的 src/App.vue 核心内容迁移到 pages/index.vue
  • 原路由(src/router)无需保留,Nuxt 会根据 pages 目录自动生成路由;
  • 原组件(src/components)可直接复用(复制到项目根目录的 components 文件夹)。
4. 运行验证
bash 复制代码
npm run dev

访问 http://localhost:3000,查看页面源码验证 SSR 生效(同新建项目步骤)。

核心逻辑总结

Vue2 + Nuxt2 实现 SSR 的本质是:

  1. 用 Nuxt2 的 universal 模式开启服务端渲染
  2. 通过 asyncData 方法在服务端预取数据(替代 Vue2 客户端请求数据的逻辑);
  3. 依赖 Nuxt2 自动处理 "服务端渲染 HTML + 客户端激活 " 的全流程(无需手动配置 vue-server-renderer 或 Webpack)。

核心验证方式:页面源码中能看到动态数据(服务端已渲染),而非客户端 JS 动态插入的空容器。验证方法blog.csdn.net/csdn_girl/a...

面试题

Vue SSR 的工作流程是什么

  1. 在服务器端运行 Vue 实例,根据路由生成 HTML。
  2. HTML 包含渲染好的内容和状态,并发送到客户端。
  3. 客户端接管页面,进行 "激活"(hydration),绑定交互逻辑。

为什么需要将 Vue 的组件和状态序列化到 HTML 中

在 SSR 中,Vue 的状态(如 Vuex 的 state)需要通过 script 标签嵌入到 HTML 中,供客户端使用

客户端和服务器端的应用实例有何不同?

  • 服务端实例专注于生成 HTML,不能直接操作 DOM
  • 客户端实例负责挂载到已有的 DOM 上,并补充交互逻辑

服务端渲染需要哪些基本配置?

如何处理路由和数据预取?

  • 路由:基于 Vue Router,确保客户端和服务端的路由一致。
  • 数据预取:在服务端预取数据后,将其传递到客户端。

SSR 如何在服务端预取数据?

  • 使用 asyncData 或在路由守卫中预取数据:
js 复制代码
const fetchData = async () => {
  const data = await fetch('api/data')
  return data.json();
};

服务端获取的数据如何传递给客户端?

  • 使用 renderToString 时,将数据注入到 HTML:
js 复制代码
<script>window.__INITIAL_STATE__ =${JSON.stringify(state)}

如何避免客户端与服务端状态不一致?

  • 客户端同步:客户端在挂载时,通过 window.INITIAL_STATE 初始化状态。

Vue SSR 如何提升 SEO?

  • 服务端返回的 HTML 包含完整内容,便于爬虫抓取。
  • 配置动态 meta 标签(如 title 和 description)提升页面权重。

如何提高 Vue SSR 的性能?

  • 使用缓存(如 Redis)减少重复渲染。
  • 压缩 HTML 和资源文件。
  • 避免不必要的组件加载,使用按需加载。

SSR 中如何避免重复渲染和多次数据请求?

  • 确保数据预取只在服务端执行,客户端通过传递的状态初始化。

SSR 项目如何处理第三方库的依赖?

  • 许多第三方库依赖 DOM,例如操作 document 或 window,在服务端渲染时可能会报错。
  • 解决方案:在 mounted 中引入这些库,确保只在客户端运行。

如何解决 SSR 与浏览器特性冲突(如 window 或 document 不存在)?

  • 浏览器特性冲突:○ 在代码中检查环境:
js 复制代码
if (typeof window !== 'undefind')
  // 浏览器相关代码
}

什么是闪屏问题?如何解决?

  • 问题:服务端生成的 HTML 和客户端激活过程中样式或内容不一致。
  • 解决方案:确保服务端和客户端使用相同的组件路由状态

Nuxt.js 如何简化 Vue SSR 的实现?

  • Nuxt.js 提供开箱即用的 SSR 支持,集成了路由、数据预取和打包优化

Nuxt.js 的 asyncData 和 fetch 有什么区别?

  • asyncData:在组件渲染前获取数据,用于静态内容。
  • fetch:在客户端和服务端均可执行,用于动态内容。

如何配置 Nuxt.js 的动态路由和 SEO?

  • 使用动态路由文件(pages/_id.vue)。
  • 在页面中定义 head 方法动态配置 meta 信息:
js 复制代码
export default {
  head() {
    return {
      title: '动态标题',
      meta: [{ name: 'description',content:'页面描述'}]
    };
  }
};

SSR 与 SSG 有什么区别?

在什么场景下应该选择 SSR 或 SSG?

SSR

  • 每次请求动态生成页面。
  • 适用于需要实时数据的应用,如电商、动态内容。

SSG

  • 在构建时生成静态 HTML 文件,部署到 CDN。
  • 适用于静态内容较多的应用,如博客、文档

面试题清单

  1. 什么是 SSR?与传统客户端渲染(CSR)有什么区别?
  2. SSR 的优点和缺点是什么?
  3. Vue SSR 的工作流程是什么?
  4. 为什么需要将 Vue 的组件和状态序列化到 HTML 中?
  5. 客户端和服务器端的应用实例有何不同?
  6. 如何使用 Vue 提供的 @vue/server-renderer 或 Nuxt.js 实现 SSR?
  7. 服务端渲染需要哪些基本配置?
  8. 如何处理路由和数据预取?
  9. SSR 如何在服务端预取数据?
  10. 服务端获取的数据如何传递给客户端?
  11. 如何避免客户端与服务端状态不一致?
  12. Vue SSR 如何提升 SEO?
  13. 如何提高 Vue SSR 的性能?
  14. SSR 中如何避免重复渲染和多次数据请求?
  15. SSR 项目如何处理第三方库的依赖?
  16. 如何解决 SSR 与浏览器特性冲突(如 window 或 document 不存在)?
  17. 什么是闪屏问题?如何解决?
  18. Nuxt.js 如何简化 Vue SSR 的实现?
  19. Nuxt.js 的 asyncData 和 fetch 有什么区别?
  20. 如何配置 Nuxt.js 的动态路由和 SEO?
  21. SSR 与 SSG 有什么区别?
  22. 在什么场景下应该选择 SSR 或 SSG?
相关推荐
晓得迷路了7 小时前
栗子前端技术周刊第 147 期 - React Router 8.4、Vite 云服务攻击、pnpm 12.4...
前端·javascript·react.js
Gauss松鼠会7 小时前
GaussDB 系统表与系统视图详解(内网运维版)
运维·服务器·网络·数据库·gaussdb·经验总结
小小de风呀8 小时前
de风——【从零开始学习Linux】(五):gcc编译器的基本使用
linux·运维·服务器
数智工坊8 小时前
RustDesk 自建服务器教程
运维·服务器
Julien20048 小时前
Docker 容器技术的本质
运维·服务器·ssh·学习方法
开开心心就好8 小时前
C盘空间不够用?一键扫描清理系统垃圾
前端·javascript·安全·支持向量机·语音识别·etcd·模拟退火算法
爱喝水的小周8 小时前
实验八 Vue‑Router 路由插件实践
前端·javascript
江屿风8 小时前
【Linux系统】【Linux 进程程序替换机制解析及自定义 Shell 核心逻辑实现 】流食般投喂
linux·运维·服务器·开发语言·笔记
ℋᙚᵐⁱᒻᵉ鲸落8 小时前
ETypeError: nameRef.value?.focus is not a functio. 设置el-input自动聚焦时报错
前端·javascript·vue.js·elementui
好不玩呀8 小时前
一次PXE服务器上IPV6问题的记录
linux·运维·服务器