18.5.4 避免交叉请求引起的状态污染
浏览器与用户是一对一,服务器与用户是一对多;在服务端把模块级的共享变量当作「请求级状态」使用,就会在不同请求之间串数据。
一、每个请求创建全新的应用实例
服务端渲染时,每次调用 render 函数都要为当前请求调用 createSSRApp 创建一个新的应用实例:
import { createSSRApp } from 'vue'
import { renderToString } from '@vue/server-renderer'
import App from 'App.vue'
// 每个请求到来都会执行一次 render 函数
async function render(url, manifest) {
// 为当前请求创建应用实例,避免不同请求共用同一实例
const app = createSSRApp(App)
const ctx = {}
const html = await renderToString(app, ctx)
return html
}
若所有请求共用一个应用实例,一个请求写入的状态会被后续请求读到,这就是交叉请求引起的状态污染。
二、组件里的模块级变量更危险
// 模块级别的全局变量
let count = 0
export default {
created() {
count++
}
}
这段代码在浏览器中不会出问题,因为浏览器与用户是一对一,每个浏览器都是独立的。
在服务器中则完全不同:服务器与用户是一对多,模块只会被加载一次,所有请求共享同一个
count,于是count会不断递增。
结论:模块级的共享模块/变量会被所有请求复用,绝不能把它当作「请求级状态」;请求级状态应存放在每次请求新建的应用实例(或组件实例)上。
相关
- 18.5.5 ClientOnly 组件:把只能在客户端渲染的内容隔离开,绕开同构带来的差异