浅谈Vue SSR 的 Cookies 问题
一个网站一旦涉及到多用户,就很难从 Cookies 中逃脱,Vue SSR 的 cookies 也真算是遇到的一个不小的问题,从开始玩 SSR 开始到现在,一共想出了3种方案,从最早的把 Cookies 注入到 state 中,到把 Cookies 注入到 global,到现在的将 Cookies 注入到组件的 asyncData 方法. 随着 Vue 的升级,第一种方案已经不再适用,第二种也有不少的限制,于是想到第三种方案,下来就说说具体实现的方法: 第一种方案第一种方案已经不再适用,这里不再细说 第二种方案思路: 将 cookies 注入到 ssr 的 context里,然后在请求 api 时读取,再追加到 axios 的header 里 1,首先在 server.js 里将 cookies 加到 context里 {
if (err) {
return errorHandler(err)
}
res.end(html)
})
之后,Vue 会把 context 加到 global.__VUE_SSR_CONTEXT__ 2,在 api.js 里读取 cookies const SSR = global.VUE_SSR_CONTEXT
const cookies = SSR.cookies || {} const parseCookie = cookies => { let cookie = '' Object.keys(cookies).forEach(item => { cookie+= item + '=' + cookies[item] + '; ' }) return cookie } export default { 为什么可以这么做?默认情况下,Vue 对于每次渲染,bundle renderer 将创建一个新的 V8 上下文并重新执行整个 bundle。应用程序代码与服务器进程隔离,所以每个访问的用户上下文都是独立的,不会互相影响. 但是从Vue@2.3.0开始,在createBundleRenderer方法的选项中,添加了runInNewContext选项,使用 runInNewContext: false,bundle 代码将与服务器进程在同一个 global 上下文中运行,所以我们不能再将 cookies 放在 global,因为这会让所有用户共用同一个 cookies. 为什么现在不这么做?那我们继续将runInNewContext设置成true,不就好了吗? 当然也是可以的,但是重新创建上下文并执行整个 bundle 还是相当昂贵的,特别是当应用很大的时候. 以我自己的博客为例,之前只有渲染 5 个路由组件,loadtest 的 rps,有 50 左右,但是后来把后台的 12 个路由组件也加到 SSR 后,rps 直接降到了个位数... 所以出现了现在的第三种方案 第三种方案思路: 将 Cookies 作为参数注入到组件的asyncData方法,然后用传参数的方法把 cookies 传给 api,不得不说这种方法很麻烦,但是这是个人能想到的比较好的方法 步骤1: 还是在 server.js 里,把 cookies 注入到 context 中 {
if (err) {
return handleError(err)
}
res.end(html)
})
步骤2: 在entry-server.js里,将cookies作为参数传给 asyncData 方法 asyncData && asyncData({
store,route: router.currentRoute,cookies: context.cookies,isServer: true,isClient: false
}))).then(() => {
context.state = store.state
context.isProd = process.env.NODE_ENV === 'production'
resolve(app)
}).catch(reject)
步骤3: 在组件里,把 cookies 做为参数给 Vuex 的 actions 步骤4: 在 Vuex 里将 cookies 做为参数给 api const state = () => ({
lists: { data: [],hasNext: 0,page: 1,path: '' },}) const actions = { const mutations = { const getters = { } export default { 这里一定要注意,state 一定要用函数返回值来初始化 state,不然会导致所有用户共用 state 步骤5: 在 api 里接收 cookies,并加到 axios 的 headers 里 const parseCookie = cookies => {
let cookie = '' Object.keys(cookies).forEach(item => { cookie+= item + '=' + cookies[item] + '; ' }) return cookie } export default { 第四种方案步骤1: 还是在 server.js 里,把 cookies 注入到 context 中 {
if (err) {
return handleError(err)
}
res.end(html)
})
步骤2: 在entry-server.js里,将cookies作为参数传给 api.setCookies 方法,api.setCookies 是什么东西后面会有 asyncData && asyncData({
store,isClient: false
}))).then(() => {
// ...
}
步骤3: 重写 api.js const parseCookie = cookies => {
let cookie = '' Object.keys(cookies).forEach(item => { cookie+= item + '=' + cookies[item] + '; ' }) return cookie } export default { 步骤4: 没有步骤4了,直接引入 api 调用即可 如果你没有将 axios 重新封装,那么也可以把第五步省略,直接在第四部把 cookies 给 axios 即可 方案 2 具体实例: 方案 3 具体实例: 方案 4 具体实例: 综上,如果你项目不大,还是直接用方案 2 吧,项目有很多页面,并且大部分页面是每个用户都一样的,可以考虑方案 3,或者你有什么更好的方法,欢迎讨论 Vue SSR 对需要 SEO,并且每个用户看到的内容都是一致的,配合缓存,将是一个非常好的体验... 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程之家。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |