VUE SSR(服务端渲染)

在这里插入图片描述

🤖 作者简介:水煮白菜王,一位前端劝退师 👻
👀 文章专栏: 前端专栏 ,记录一下平时在博客写作中,总结出的一些开发技巧和知识归纳总结✍。
感谢支持💕💕💕

目录

  • 总览
    • 什么是 SSR?
    • 为什么要用 SSR?
    • SSR vs. SSG
  • 基础教程
    • 渲染一个应用
    • 客户端激活
    • 代码结构
  • 更通用的解决方案
    • Nuxt
    • Quasar​
    • Vite SSR​
  • 书写 SSR 友好的代码
    • 服务端的响应性
    • 组件生命周期钩子
    • 访问平台特有 API
    • 跨请求状态污染
    • 激活不匹配​
    • 消除激活不匹配
    • 自定义指令
    • Teleports
  • 服务器渲染难点与亮点

本文将基于Vue官方提供的介绍进行切入,详细复述Vue文档SSR的相关知识点为基础 😀。之后进行梳理并总结SSR服务器渲染知识,总结SSR在实际实施时一些难点和亮点 🚀。

总览

什么是 SSR?

Vue.js 是一个用于构建客户端应用的框架。默认情况下,Vue 组件的职责是在浏览器中生成和操作 DOM。然而,Vue 也支持将组件在服务端直接渲染成 HTML 字符串,作为服务端响应返回给浏览器,最后在浏览器端将静态的 HTML“激活”(hydrate) 为能够交互的客户端应用。

一个由服务端渲染的 Vue.js 应用也可以被认为是“同构的”(Isomorphic) 或“通用的”(Universal),因为应用的大部分代码同时运行在服务端和客户端。

为什么要用 SSR?

与客户端的单页应用 (SPA) 相比,SSR 的优势主要在于:

  • 更快的首屏加载:这一点在慢网速或者运行缓慢的设备上尤为重要。服务端渲染的 HTML 无需等到所有的 JavaScript
    都下载并执行完成之后才显示,所以你的用户将会更快地看到完整渲染的页面。除此之外,数据获取过程在首次访问时在服务端完成,相比于从客户端获取,可能有更快的数据库连接。这通常可以带来更高的核心
    Web 指标评分、更好的用户体验,而对于那些“首屏加载速度与转化率直接相关”的应用来说,这点可能至关重要。

  • 统一的心智模型:你可以使用相同的语言以及相同的声明式、面向组件的心智模型来开发整个应用,而不需要在后端模板系统和前端框架之间来回切换。

  • 更好的 SEO:搜索引擎爬虫可以直接看到完全渲染的页面。

截至目前,Google 和 Bing 可以很好地对同步 JavaScript 应用进行索引。这里的“同步”是关键词。如果你的应用以一个 loading 动画开始,然后通过 Ajax 获取内容,爬虫并不会等到内容加载完成再抓取。也就是说,如果 SEO 对你的页面至关重要,而你的内容又是异步获取的,那么 SSR 可能是必需的。

使用 SSR 时还有一些权衡之处需要考量:

  • 开发中的限制。浏览器端特定的代码只能在某些生命周期钩子中使用;一些外部库可能需要特殊处理才能在服务端渲染的应用中运行。

  • 更多的与构建配置和部署相关的要求。服务端渲染的应用需要一个能让 Node.js 服务器运行的环境,不像完全静态的 SPA 那样可以部署在任意的静态文件服务器上。

  • 更高的服务端负载。在 Node.js 中渲染一个完整的应用要比仅仅托管静态文件更加占用 CPU 资源,因此如果你预期有高流量,请为相应的服务器负载做好准备,并采用合理的缓存策略。

在为你的应用使用 SSR 之前,你首先应该问自己是否真的需要它。这主要取决于首屏加载速度对应用的重要程度。例如,如果你正在开发一个内部的管理面板,初始加载时的那额外几百毫秒对你来说并不重要,这种情况下使用 SSR 就没有太多必要了。然而,在内容展示速度极其重要的场景下,SSR 可以尽可能地帮你实现最优的初始加载性能。

SSR vs. SSG

静态站点生成 (Static-Site Generation,缩写为 SSG),也被称为预渲染,是另一种流行的构建快速网站的技术。如果用服务端渲染一个页面所需的数据对每个用户来说都是相同的,那么我们可以只渲染一次,提前在构建过程中完成,而不是每次请求进来都重新渲染页面。预渲染的页面生成后作为静态 HTML 文件被服务器托管。

SSG 保留了和 SSR 应用相同的性能表现:它带来了优秀的首屏加载性能。同时,它比 SSR 应用的花销更小,也更容易部署,因为它输出的是静态 HTML 和资源文件。这里的关键词是静态:SSG 仅可以用于提供静态数据的页面,即数据在构建期间就是已知的,并且在多次请求之间不能被改变。每当数据变化时,都需要重新部署。

如果你调研 SSR 只是为了优化为数不多的营销页面的 SEO (例如 //about/contact 等),那么你可能需要 SSG 而不是 SSR。SSG 也非常适合构建基于内容的网站,比如文档站点或者博客。事实上,你现在正在阅读的这个网站就是使用 VitePress 静态生成的,它是一个由 Vue 驱动的静态站点生成器。

基础教程

渲染一个应用

  1. 创建一个新的文件夹,cd 进入
  2. 执行 npm init -y
  3. package.json 中添加 “type”: “module” 使 Node.js 以 ES modules mode 运行
  4. 执行 npm install vue
  5. 创建一个 example.js 文件:
// 此文件运行在 Node.js 服务器上
import { createSSRApp } from 'vue'
// Vue 的服务端渲染 API 位于 `vue/server-renderer` 路径下
import { renderToString } from 'vue/server-renderer'const app = createSSRApp({data: () => ({ count: 1 }),template: `<button @click="count++">{{ count }}</button>`
})renderToString(app).then((html) => {console.log(html)
})

接着运行:

> node example.js

它应该会在命令行中打印出如下内容:

<button>1</button>

renderToString() 接收一个 Vue 应用实例作为参数,返回一个 Promise,当 Promise resolve 时得到应用渲染的 HTML。当然你也可以使用 Node.js Stream API 或者 Web Streams API 来执行流式渲染。查看 SSR API 参考获取完整的相关细节。

然后我们可以把 Vue SSR 的代码移动到一个服务器请求处理函数里,它将应用的 HTML 片段包装为完整的页面 HTML。接下来的几步我们将会使用 express:

  • 执行 npm install express
  • 创建下面的 server.js 文件:
import express from 'express'
import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'const server = express()server.get('/', (req, res) => {const app = createSSRApp({data: () => ({ count: 1 }),template: `<button @click="count++">{{ count }}</button>`})renderToString(app).then((html) => {res.send(`<!DOCTYPE html><html><head><title>Vue SSR Example</title></head><body><div id="app">${html}</div></body></html>`)})
})server.listen(3000, () => {console.log('ready')
})

最后,执行 node server.js,访问 http://localhost:3000。你应该可以看到页面中的按钮了。

在 StackBlitz 上试试

客户端激活

如果你点击该按钮,你会发现数字并没有改变。这段 HTML 在客户端是完全静态的,因为我们没有在浏览器中加载 Vue。

为了使客户端的应用可交互,Vue 需要执行一个激活步骤。在激活过程中,Vue 会创建一个与服务端完全相同的应用实例,然后将每个组件与它应该控制的 DOM 节点相匹配,并添加 DOM 事件监听器。

为了在激活模式下挂载应用,我们应该使用 createSSRApp() 而不是 createApp():

// 该文件运行在浏览器中
import { createSSRApp } from 'vue'const app = createSSRApp({// ...和服务端完全一致的应用实例
})// 在客户端挂载一个 SSR 应用时会假定
// HTML 是预渲染的,然后执行激活过程,
// 而不是挂载新的 DOM 节点
app.mount('#app')

代码结构

想想该如何在客户端复用服务端的应用实现。这时就需要开始考虑 SSR 应用中的代码结构了——如何在服务器和客户端之间共享相同的应用代码呢?

这里将演示最基础的设置。首先,将应用的创建逻辑拆分到一个单独的文件 app.js 中:

// app.js (在服务器和客户端之间共享)
import { createSSRApp } from 'vue'export function createApp() {return createSSRApp({data: () => ({ count: 1 }),template: `<button @click="count++">{{ count }}</button>`})
}

该文件及其依赖项在服务器和客户端之间共享——我们称它们为通用代码。编写通用代码时有一些注意事项,我们将在下面讨论。

我们在客户端入口导入通用代码,创建应用并执行挂载:

// client.js
import { createApp } from './app.js'createApp().mount('#app')

服务器在请求处理函数中使用相同的应用创建逻辑:

// server.js (不相关的代码省略)
import { createApp } from './app.js'server.get('/', (req, res) => {const app = createApp()renderToString(app).then(html => {// ...})
})

此外,为了在浏览器中加载客户端文件,我们还需要:

  1. server.js 中添加 server.use(express.static('.')) 来托管客户端文件。
  2. <script type="module" src="/client.js"></script> 添加到 HTML 外壳以加载客户端入口文件。
  3. 通过在 HTML 外壳中添加 Import Map 以支持在浏览器中使用 import * from 'vue'

在 StackBlitz 上尝试完整的示例。按钮现在可以交互了!

更通用的解决方案

从上面的例子到一个生产就绪的 SSR 应用还需要很多工作。我们将需要:

  • 支持 Vue 单文件组件且满足其他构建步骤要求。事实上,我们需要为同一个应用执行两次构建过程:一次用于客户端,一次用于服务器。

Vue 组件用在 SSR 时的编译产物不同——模板被编译为字符串拼接而不是 render 函数,以此提高渲染性能。

  • 在服务器请求处理函数中,确保返回的 HTML 包含正确的客户端资源链接和最优的资源加载提示 (如 prefetch 和 preload)。我们可能还需要在 SSR 和 SSG 模式之间切换,甚至在同一个应用中混合使用这两种模式。

  • 以一种通用的方式管理路由、数据获取和状态存储。
    完整的实现会非常复杂,并且取决于你选择使用的构建工具链。因此,我们强烈建议你使用一种更通用的、更集成化的解决方案,帮你抽象掉那些复杂的东西。下面推荐几个 Vue 生态中的 SSR 解决方案。

Nuxt

Nuxt 是一个构建于 Vue 生态系统之上的全栈框架,它为编写 Vue SSR 应用提供了丝滑的开发体验。更棒的是,你还可以把它当作一个静态站点生成器来用!我们强烈建议你试一试。

Quasar​

Quasar 是一个基于 Vue 的完整解决方案,它可以让你用同一套代码库构建不同目标的应用,如 SPA、SSR、PWA、移动端应用、桌面端应用以及浏览器插件。除此之外,它还提供了一整套 Material Design 风格的组件库。

Vite SSR​

Vite 提供了内置的 Vue 服务端渲染支持,但它在设计上是偏底层的。如果你想要直接使用 Vite,可以看看 vite-plugin-ssr,一个帮你抽象掉许多复杂细节的社区插件。

你也可以在这里查看一个使用手动配置的 Vue + Vite SSR 的示例项目,以它作为基础来构建。请注意,这种方式只有在你有丰富的 SSR 和构建工具经验,并希望对应用的架构做深入的定制时才推荐使用。

书写 SSR 友好的代码

无论你的构建配置或顶层框架的选择如何,下面的原则在所有 Vue SSR 应用中都适用。

服务端的响应性

在 SSR 期间,每一个请求 URL 都会映射到我们应用中的一个期望状态。因为没有用户交互和 DOM 更新,所以响应性在服务端是不必要的。为了更好的性能,默认情况下响应性在 SSR 期间是禁用的。

组件生命周期钩子

因为没有任何动态更新,所以像 mounted 或者 updated 这样的生命周期钩子不会在 SSR 期间被调用,而只会在客户端运行。只有 beforeCreatecreated 这两个钩子会在 SSR 期间被调用。

你应该避免在 beforeCreatecreated中使用会产生副作用且需要被清理的代码。这类副作用的常见例子是使用 setInterval 设置定时器。我们可能会在客户端特有的代码中设置定时器,然后在 beforeUnmountunmounted 中清除。然而,由于 unmount 钩子不会在 SSR 期间被调用,所以定时器会永远存在。为了避免这种情况,请将含有副作用的代码放到 mounted 中。

访问平台特有 API

通用代码不能访问平台特有的 API,如果你的代码直接使用了浏览器特有的全局变量,比如 windowdocument,他们会在 Node.js 运行时报错,反过来也一样。

对于在服务器和客户端之间共享,但使用了不同的平台 API 的任务,建议将平台特定的实现封装在一个通用的 API 中,或者使用能为你做这件事的库。例如你可以使用 node-fetch 在服务端和客户端使用相同的 fetch API。

对于浏览器特有的 API,通常的方法是在仅客户端特有的生命周期钩子中惰性地访问它们,例如 mounted

请注意,如果一个第三方库编写时没有考虑到通用性,那么要将它集成到一个 SSR 应用中可能会很棘手。你或许可以通过模拟一些全局变量来让它工作,但这只是一种 hack 手段并且可能会影响到其他库的环境检测代码。

跨请求状态污染

在状态管理一章中,我们介绍了一种使用响应式 API 的简单状态管理模式。而在 SSR 环境中,这种模式需要一些额外的调整。

上述模式在一个 JavaScript 模块的根作用域中声明共享的状态。这是一种单例模式——即在应用的整个生命周期中只有一个响应式对象的实例。这在纯客户端的 Vue 应用中是可以的,因为对于浏览器的每一个页面访问,应用模块都会重新初始化。

然而,在 SSR 环境下,应用模块通常只在服务器启动时初始化一次。同一个应用模块会在多个服务器请求之间被复用,而我们的单例状态对象也一样。如果我们用单个用户特定的数据对共享的单例状态进行修改,那么这个状态可能会意外地泄露给另一个用户的请求。我们把这种情况称为跨请求状态污染。

从技术上讲,我们可以在每个请求上重新初始化所有 JavaScript 模块,就像我们在浏览器中所做的那样。但是,初始化 JavaScript 模块的成本可能很高,因此这会显著影响服务器性能。

推荐的解决方案是在每个请求中为整个应用创建一个全新的实例,包括 router 和全局 store。然后,我们使用应用层级的 provide 方法来提供共享状态,并将其注入到需要它的组件中,而不是直接在组件中将其导入:

// app.js (在服务端和客户端间共享)
import { createSSRApp } from 'vue'
import { createStore } from './store.js'// 每次请求时调用
export function createApp() {const app = createSSRApp(/* ... */)// 对每个请求都创建新的 store 实例const store = createStore(/* ... */)// 提供应用级别的 storeapp.provide('store', store)// 也为激活过程暴露出 storereturn { app, store }
}

像 Pinia 这样的状态管理库在设计时就考虑到了这一点。请参考 Pinia 的 SSR 指南以了解更多细节。

激活不匹配​

如果预渲染的 HTML 的 DOM 结构不符合客户端应用的期望,就会出现激活不匹配。最常见的激活不匹配是以下几种原因导致的:

  1. 组件模板中存在不符合规范的 HTML 结构,渲染后的 HTML 被浏览器原生的 HTML 解析行为纠正导致不匹配。举例来说,一个常见的错误是 <div > 不能被放在 <p> 中:
<p><div>hi</div></p>

如果我们在服务器渲染的 HTML 中出现这样的代码,当遇到 <div > 时,浏览器会结束第一个 <p>,并解析为以下 DOM 结构:

<p></p>
<div>hi</div>
<p></p>
  1. 渲染所用的数据中包含随机生成的值。由于同一个应用会在服务端和客户端执行两次,每次执行生成的随机数都不能保证相同。避免随机数不匹配有两种选择:
    2-1 利用 v-if + onMounted 让需要用到随机数的模板只在客户端渲染。你所用的上层框架可能也会提供简化这个用例的内置 API,比如 VitePress 的 <ClientOnly> 组件。
    2-2 使用一个能够接受随机种子的随机数生成库,并确保服务端和客户端使用同样的随机数种子 (比如把种子包含在序列化的状态中,然后在客户端取回)。
  2. 服务端和客户端的时区不一致。有时候我们可能会想要把一个时间转换为用户的当地时间,但在服务端的时区跟用户的时区可能并不一致,我们也并不能可靠的在服务端预先知道用户的时区。这种情况下,当地时间的转换也应该作为纯客户端逻辑去执行。

当 Vue 遇到激活不匹配时,它将尝试自动恢复并调整预渲染的 DOM 以匹配客户端的状态。这将导致一些渲染性能的损失,因为需要丢弃不匹配的节点并渲染新的节点,但大多数情况下,应用应该会如预期一样继续工作。尽管如此,最好还是在开发过程中发现并避免激活不匹配。

消除激活不匹配

在 Vue 3.5+ 中,可以使用 data-allow-mismatch attribute 有选择性地消除无法避免的激活不匹配警告。

自定义指令

因为大多数的自定义指令都包含了对 DOM 的直接操作,所以它们会在 SSR 时被忽略。但如果你想要自己控制一个自定义指令在 SSR 时应该如何被渲染 (即应该在渲染的元素上添加哪些 attribute),你可以使用 getSSRProps 指令钩子:

const myDirective = {mounted(el, binding) {// 客户端实现:// 直接更新 DOMel.id = binding.value},getSSRProps(binding) {// 服务端实现:// 返回需要渲染的 prop// getSSRProps 只接收一个 binding 参数return {id: binding.value}}
}

Teleports

在 SSR 的过程中 Teleport 需要特殊处理。如果渲染的应用包含 Teleport,那么其传送的内容将不会包含在主应用渲染出的字符串中。在大多数情况下,更推荐的方案是在客户端挂载时条件式地渲染 Teleport。

如果你需要激活 Teleport 内容,它们会暴露在服务端渲染上下文对象的 teleports 属性下:

const ctx = {}
const html = await renderToString(app, ctx)console.log(ctx.teleports) // { '#teleported': 'teleported content' }

跟主应用的 HTML 一样,你需要自己将 Teleport 对应的 HTML 嵌入到最终页面上的正确位置处。

请避免在 SSR 的同时把 Teleport 的目标设为 body——通常 <body> 会包含其他服务端渲染出来的内容,这会使得 Teleport 无法确定激活的正确起始位置。
推荐用一个独立的只包含 teleport 的内容的容器,例如 <div id="teleported"></div>

服务器渲染难点与亮点

Vue SSR(服务端渲染)对 SEO(搜索引擎优化)有明显的优势,因为它可以直接将完整的 HTML 页面返回给搜索引擎爬虫,这样爬虫能够更好地解析页面内容,提升 SEO 排名。然而,实际实施时也有一些难点和亮点。

难点:

  1. SSR 与 CSR 之间的同步问题: Vue SSR 渲染的是服务器端的静态 HTML 页面,前端会在加载后通过客户端的 Vue 实例来激活动态功能(例如,交互)。这种双重渲染可能会导致“闪烁”或内容的不同步,即页面在加载时先显示服务器渲染的内容,然后再切换到客户端渲染的内容。这种过程可能会影响用户体验,甚至可能被搜索引擎误判为无效内容。
  2. 缓存策略: 由于 Vue SSR 是在服务器上动态渲染的,如何缓存页面内容成为一个问题。没有合适的缓存机制,页面的渲染会导致性能瓶颈。为了提高渲染速度,可能需要在服务器端做动态内容的缓存或静态化处理。
  3. SEO 数据注入问题: 在 Vue SSR 中,页面内容是动态渲染的,可能涉及到在组件加载之前就需要将 SEO 相关的元数据(如标题、描述、关键词等)注入到页面中。如果这些数据没有在服务端渲染时注入,爬虫可能无法获取到正确的信息,从而影响 SEO。
  4. 环境配置与构建复杂性: Vue SSR 配置相对复杂,需要使用 Node.js 作为服务器端,合理配置 Webpack、Babel 等构建工具,以保证服务端和客户端的代码都能正常工作。调试和开发过程中,可能需要同时关注客户端和服务端的日志,调试难度较大。

亮点:

  1. SEO 优化: SSR 最直接的亮点是其对 SEO 的增强。搜索引擎可以直接抓取到完整的 HTML 页面,提升了爬虫的可见性和页面的索引速度,避免了传统客户端渲染(CSR)中爬虫无法解析 JavaScript 内容的问题。
  2. 初次加载性能: 由于服务器渲染的页面可以直接呈现给用户,浏览器渲染时不需要等待 JavaScript 加载并执行,从而提高了页面的首屏加载速度,提升了用户体验和搜索引擎的评价。
  3. 统一的渲染逻辑: 使用 Vue SSR 时,可以在客户端和服务端共享同一套组件和渲染逻辑。这样,开发者只需要写一次代码,而不需要分别为客户端和服务端维护两套逻辑,减少了开发工作量和出错的可能性。
  4. 增强的用户体验: 由于页面内容由服务器端直接返回,用户能够更快地看到完整的页面内容,尤其在移动端和网络较慢的情况下,SSR 可以有效提升页面加载速度,减少闪屏和白屏现象。

Vue SSR 的 Node 中间层服务作为服务端渲染的核心部分,它在应用的部署和维护上有一些特有的难点,主要集中在以下几个方面:

难点:

  1. Node 服务的部署和扩展性: Vue SSR 的中间层通常使用 Node.js 进行渲染,因此部署的架构需要保证 Node 服务能够高效运行。这意味着:
    ○ 负载均衡:在高并发的情况下,需要通过负载均衡策略分发请求到多个 Node 实例。如果使用的是单机部署,性能会受到瓶颈限制。
    ○ 容器化和编排:现代部署中,使用 Docker 容器化和 Kubernetes 编排已成为常见的做法,但这也增加了运维的复杂度。需要合理设计服务的容器配置和资源调度。
  2. 服务器端渲染的性能优化:
    ○ 缓存策略:SSR 会带来较高的计算负载,尤其是对于动态数据多的页面。为了减少服务器的负担,可能需要实现页面或数据的缓存策略。例如,缓存渲染后的 HTML、API 请求结果等。
    ○ 数据预加载和异步处理:确保 SSR 时可以高效预加载必要的数据,避免页面加载时因数据请求而造成延迟。如何合理安排数据加载的顺序和方式也会影响性能。
  3. Node 服务的状态管理与全局性问题:
    ○ 在 Node.js 中,服务端渲染需要保证请求之间的隔离性,避免数据污染和状态混乱。SSR 渲染过程会共享同一个服务器进程,因此要确保每次请求的渲染不会互相干扰。
    ○ 全局状态的处理:例如,Vuex 状态管理需要特别注意服务端渲染时的状态注入和恢复。状态需要在服务端渲染完成后正确传递到客户端,避免出现数据不一致的问题。
  4. 错误监控与日志管理:
    ○ SSR 渲染过程中可能会遇到各种错误,包括网络请求失败、渲染异常、模板渲染错误等。需要确保有完善的错误监控和日志收集机制(例如:Sentry、LogRocket 等)。
    ○ 实时日志:因为 Node 服务器是动态渲染内容,无法像传统静态页面那样通过简单的调试获取详细的日志,所以维护过程需要实时的错误监控和日志记录,帮助开发人员快速定位问题。
  5. 热更新和部署管理:
    ○ 代码热更新:SSR 服务需要支持开发和生产环境中的热更新(Hot Module Replacement,HMR)。这对于在开发过程中快速调试、调优至关重要,但也增加了开发与部署过程中的复杂性。
    ○ 部署与滚动更新:在 Node 服务上线时,通常使用滚动更新(Rolling Update)策略,避免全量下线。这要求在部署时确保 Node 服务不会造成停机时间,且能够平稳地进行版本更新。
  6. 依赖管理与版本兼容:
    ○ 在服务端渲染的场景下,Node 服务需要处理大量的依赖库(如 Vue、webpack、babel 等),如果依赖版本不兼容,可能会导致渲染出错。需要定期检查依赖关系并进行版本更新。
    ○ 服务器的 Node 环境和前端项目的依赖环境需保持一致,以避免开发和生产环境之间的差异影响渲染结果。

亮点与解决方案:

  1. 使用 Docker 容器化部署:
    ○ 通过容器化,将 Node 中间层服务封装成 Docker 镜像,确保开发、测试和生产环境的一致性。
    ○ 可以借助 Kubernetes 或 Docker Compose 管理多实例服务的扩展、负载均衡、健康检查等,提高部署的灵活性和可维护性。
  2. 使用 CDN 和缓存策略:
    ○ 针对 SSR 输出的 HTML,可以结合 CDN 来缓存静态页面内容,减少服务器压力。对于动态内容,可以使用服务端缓存(例如 Redis)来缓存 API 请求结果或渲染后的页面,从而减少重复渲染的负载。
  3. 利用现代 CI/CD 工具链:
    ○ 使用 GitLab CI、GitHub Actions 或 Jenkins 等 CI/CD 工具,自动化构建、测试、部署和上线流程。部署时结合蓝绿发布(Blue-Green Deployment)策略,可以平滑地进行版本更新,避免服务停机。
  4. 使用日志管理与监控工具:
    ○ 集成日志管理工具(如 ELK Stack、Prometheus、Grafana)对 SSR 服务进行实时监控,确保能够及时发现并解决潜在的问题。
    ○ 在生产环境中启用错误跟踪工具(如 Sentry),实时捕捉并报告错误,减少运维和开发人员的排查时间。
  5. 服务端渲染框架的优化:
    ○ 借助像 Nuxt.js 这样的 SSR 框架,它自带了许多性能优化和开发便利工具,能大大简化 Vue SSR 服务端渲染的配置和部署过程,并提供内置的缓存机制和热更新功能。

维护中的注意事项:

  • 性能监控:定期检查 SSR 服务的性能指标,监控响应时间、吞吐量、服务器负载等,确保服务的健康运行。
  • 日志清理:由于 SSR 服务可能会生成大量日志文件,需要定期清理或归档日志文件,以免占用过多存储资源。
  • 安全性:确保服务端渲染的过程中不暴露敏感数据,防止 SSR 漏洞,如跨站脚本(XSS)、跨站请求伪造(CSRF)等。

如果你的项目同样采用了SSR架构,,是否在部署和维护过程中遇到具体的难题?

在这里插入图片描述
如果你觉得这篇文章对你有帮助,请点赞 👍、收藏 👏 并关注我!👀
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/79459.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ARCGIS国土超级工具集1.5更新说明

ARCGIS国土超级工具集V1.5版本更新说明&#xff1a;因作者近段时间工作比较忙及正在编写ARCGISPro国土超级工具集&#xff08;截图附后&#xff09;的原因&#xff0c;故本次更新为小更新&#xff08;没有增加新功能&#xff0c;只更新了已有的工具&#xff09;。本次更新主要修…

刘鑫炜履新共工新闻社新媒体研究院院长,赋能媒体融合新征程

2025年4月18日&#xff0c;大湾区经济网战略媒体共工新闻社正式对外宣布一项重要人事任命&#xff1a;聘任蚂蚁全媒体总编刘鑫炜为新媒体研究院第一任院长。这一举措&#xff0c;无疑是对刘鑫炜在新媒体领域卓越专业能力与突出行业贡献的又一次高度认可&#xff0c;也预示着共工…

java基础从入门到上手(九):Java - List、Set、Map

一、List集合 List 是一种用于存储有序元素的集合接口&#xff0c;它是 java.util 包中的一部分&#xff0c;并且继承自 Collection 接口。List 接口提供了多种方法&#xff0c;用于按索引操作元素&#xff0c;允许元素重复&#xff0c;并且保持插入顺序。常用的 List 实现类包…

UWP发展历程

通用Windows平台(UWP)发展历程 引言 通用Windows平台(Universal Windows Platform, UWP)是微软为实现"一次编写&#xff0c;处处运行"的愿景而打造的现代应用程序平台。作为微软统一Windows生态系统的核心战略组成部分&#xff0c;UWP代表了从传统Win32应用向现代应…

git忽略已跟踪的文件/指定文件

在项目开发中&#xff0c;有时候我们并不需要git跟踪所有文件&#xff0c;而是需要忽略掉某些指定的文件或文件夹&#xff0c;怎么操作呢&#xff1f;我们分两种情况讨论&#xff1a; 1. 要忽略的文件之前并未被git跟踪 这种情况常用的方法是在项目的根目录下创建和编辑.gitig…

AI 组件库是什么?如何影响UI的开发?

AI组件库是基于人工智能技术构建的、面向用户界面&#xff08;UI&#xff09;开发的预制模块集合。它们结合了传统UI组件&#xff08;如按钮、表单、图表&#xff09;与AI能力&#xff08;如机器学习、自然语言处理、计算机视觉&#xff09;&#xff0c;旨在简化开发流程并增强…

【Win】 cmd 执行curl命令时,输出 ‘命令管道位置 1 的 cmdlet Invoke-WebRequest 请为以下参数提供值: Uri: ’ ?

1.原因&#xff1a; 有一个名为 Invoke-WebRequest 的 CmdLet&#xff0c;其别名为 curl。因此&#xff0c;当您执行此命令时&#xff0c;它会尝试使用 Invoke-WebRequest&#xff0c;而不是使用 curl。 2.解决办法 在cmd中输入如下命令删除这个curl别名&#xff1a; Remov…

UE5 UE循环体里怎么写延迟

注&#xff1a;需要修改UE循环蓝图节点或者自己新建个蓝图宏库把UE循环节点的原来代码粘贴进去修改。 一、For Loop With Delay 二、For Each Loop With Delay 示例使用&#xff1a; 标注参考出处&#xff1a;分享UE5自制Loop with delay宏&#xff0c;在loop循环中添加执行…

IP检测工具“ipjiance”

目录 IP质量检测 应用场景 对网络安全的贡献 对网络管理的帮助 对用户决策的辅助作用 IP质量检测 检测IP的网络提供商&#xff1a;通过ASN&#xff08;自治系统编号&#xff09;识别IP地址所属的网络运营商&#xff0c;例如电信、移动、联通等。 识别网络类型&#xff1…

[工具]Java xml 转 Json

[工具]Java xml 转 Json 依赖 <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all --> <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.37</version> </dependen…

vue3 传参 传入变量名

背景&#xff1a; 需求是&#xff1a;在vue框架中&#xff0c;接口传参我们需要穿“变量名”&#xff0c;而不是字符串 通俗点说法是&#xff1a;在网络接口请求的时候&#xff0c;要传属性名 效果展示&#xff1a; vue2核心代码&#xff1a; this[_keyParam] vue3核心代码&…

spring响应式编程系列:总体流程

目录 示例 程序流程 just subscribe new LambdaMonoSubscriber ​​​​​​​MonoJust.subscribe ​​​​​​​new Operators.ScalarSubscription ​​​​​​​onSubscribe ​​​​​​​request ​​​​​​​onNext 时序图 类图 数据发布者 MonoJust …

基于slimBOXtv 9.16 V2-晶晨S905L3A/ S905L3AB-Mod ATV-Android9.0-线刷通刷固件包

基于slimBOXtv 9.16 V2-晶晨S905L3A&#xff0f; S905L3AB-Mod ATV-Android9.0-线刷通刷固件包&#xff0c;基于SlimBOXtv 9 修改而来&#xff0c;贴近于原生ATV&#xff0c;仅支持晶晨S905L3A&#xff0f; S905L3AB芯片刷机。 适用型号&#xff1a;M401A、CM311-1a、CM311-1s…

使用droidrun库实现AI控制安卓手机

使用droidrun库实现AI控制安卓手机 介绍 DroidRun 是一个框架&#xff0c;通过LLM代理控制 Android 设备。它允许您使用自然语言命令自动化 Android 设备交互。 安装环境 安装源码依赖 git clone https://github.com/droidrun/droidrun.git cd droidrun conda create --nam…

知识库建设全流程指南(AI时代优化版)

知识库建设全流程指南&#xff08;AI时代优化版&#xff09; ​​一、知识库建设的战略定位​​ ​​核心价值锚点​​ ​​AI时代基建​​&#xff1a;知识库是GEO优化的核心载体&#xff0c;决定内容被AI引用的概率权重​​动态护城河​​&#xff1a;结构化知识体系可抵御算…

2025年03月中国电子学会青少年软件编程(Python)等级考试试卷(五级)真题

青少年软件编程&#xff08;Python&#xff09;等级考试试卷&#xff08;五级&#xff09; 分数&#xff1a;100 题数&#xff1a;38 答案解析&#xff1a;https://blog.csdn.net/qq_33897084/article/details/147341437 一、单选题(共25题&#xff0c;共50分) 1. 以下哪个选…

基于RRT的优化器:一种基于快速探索随机树算法的新型元启发式算法

受机器人路径规划中常用的快速探索随机树&#xff08;RRT&#xff09;算法的搜索机制的启发&#xff0c;我们提出了一种新颖的元启发式算法&#xff0c;称为基于RRT的优化器&#xff08;RRTO&#xff09;。这是首次将RRT算法的概念与元启发式算法相结合。RRTO的关键创新是其三种…

进阶篇|CAN FD 与性能优化

引言 1. CAN vs. CAN FD 对比 2. CAN FD 帧结构详解

【随身WiFi】随身WiFi Debian系统优化教程

0.操作前必看 本教程基于Debian系统进行优化&#xff0c;有些操作对随身WiFi来说可能会带来负优化&#xff0c;根据需要选择。 所有操作需要在root用户环境下运行&#xff0c;否则都要加sudo 随身wifi Debian系统&#xff0c;可以去某安的随声WiFi模块自行搜索刷机 点赞&am…

【Pandas】pandas DataFrame where

Pandas2.2 DataFrame Indexing, iteration 方法描述DataFrame.head([n])用于返回 DataFrame 的前几行DataFrame.at快速访问和修改 DataFrame 中单个值的方法DataFrame.iat快速访问和修改 DataFrame 中单个值的方法DataFrame.loc用于基于标签&#xff08;行标签和列标签&#…