前端服务端渲染 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?
相关推荐
TAEHENGV2 小时前
目标列表模块 Cordova 与 OpenHarmony 混合开发实战
服务器·数据库
南山nash2 小时前
Linux 系统如何释放内存
linux·运维·服务器
C_心欲无痕2 小时前
vue3 - shallowReactive浅层响应式对象(只对顶层属性)
前端·javascript·vue.js
AY呀2 小时前
新手必读:React组件从入门到精通,一篇文章搞定所有核心概念
前端·javascript·react.js
阿钱真强道2 小时前
02-COAP ubuntu 下 coap 使用及测试
运维·服务器
用户12039112947262 小时前
LangChain 实战:让 LLM 拥有记忆与结构化输出能力
javascript·langchain·llm
Maxkim2 小时前
「✍️JS原子笔记 」一文搞懂 call、apply、bind 特征及手写实现
前端·javascript·面试
A24207349302 小时前
深入理解JS DOM:从基础操作到性能优化的全面指南
开发语言·javascript·ecmascript
Zyx20072 小时前
手写 `new`:揭开 JavaScript 实例化背后的秘密
javascript