Vue SSRのCookies問題について話します。
一つのサイトがマルチユーザーに触れると、Cookiesからの脱出が難しくなります。Vue SSRのcookiesも本当に大きな問題に遭遇しました。SSRを始めてから今までの3つの案を考えました。最初のCookiesをstateに注入し、Cookiesをglobalに注入するまで、CookiesをDaynanctaに注入する方法です。
Vueのアップグレードに従って、第一の方案はもう適用されなくなりました。第二の方案も多くの制限があります。そこで第三の方案を思い付きました。具体的に実現する方法を教えてください。
第一案
第一の案はもう適用されなくなりました。ここで詳しく説明しません。
第二の案
アイデア:cookiesをssrのcontextに注入し、apiを要求する時に読み、axiosのheaderに追加します。
1,まずserver.jsでcookiesをcontextに追加します。
2,appi.jsでcookiesを読みます。
デフォルトでは、Vueはレンダリング毎に、新しいV 8コンテキストを作成し、Windows全体を再実行します。アプリケーションコードはサーバプロセスから分離されていますので、各アクセスのユーザーコンテキストは独立しています。
しかし、[email protected]最初に、createBundeleRenderer方法のオプションに、run InNewConteetオプションを追加しました。run InNewConteetを使用します。false、bundleコードはサーバープロセスと同じglobalコンテキストで実行されます。だから、cookiesをglobalに置くことはできません。
なぜ今はそうしないですか?
私達は引き続きrunInNewContectをtrueに設定したらいいじゃないですか?もちろんいいですが、コンテキストを再作成して、全体のWindowsを実行するのはかなり高価です。
自分のブログを例にとって、これまでは5つのルートコンポーネントしか描画していませんでした。loadtestのrpsは50ぐらいありましたが、その後、バックグラウンドの12つのルートコンポーネントをSSRに加えた後、rpsは直接桁を下げました。
だから今の第三の案が現れました。
第三の案
考え方:CookiesをパラメータとしてコンポーネントのasyncDataに注入し、パラメータを伝える方法で、cookiesをapiに伝えます。この方法は厄介だと言わざるを得ませんが、これは個人で考えられるより良い方法です。
ステップ1:
それともserver.jsでcookiesをcontextに注入しますか?
entry-server.jsで、cookiesをパラメータとしてasyncDataに送る方法
コンポーネントの中で、cookiesをパラメータにしてVuexのactionsにあげます。
Vuexでcookiesをパラメータとしてapiにあげます。
ステップ5:
apiの中でcookiesを受け取って、そしてaxiosのheadersの中に加えます。
ステップ1:
それともserver.jsでcookiesをcontextに注入しますか?
entry-server.jsで、cookiesをパラメータとしてapi.set Cookiesに送る方法は、appi.set Cookiesは何ですか?
appi.jsを書き換える
ステップ4がないので、直接にアプリを導入して呼び出してもいいです。
もしaxiosを再パッケージしなかったら、第五段階を省略して、直接第四部でaxiosにcookiesを渡してもいいです。
シナリオ2の具体例:https://github.com/lincenying/mmf-blog-vue2-ssr
シナリオ3の具体例:https://github.com/lincenying/mmf-blog-vue2-pwa-ssr
シナリオ4の具体例:https://github.com/lincenying/mmf-blog-vue2-pwa-ssr
以上のように、プロジェクトが大きくないなら、直接案を使いましょう。プロジェクトは多くのページがあります。そして、ほとんどのページはユーザーごとに同じです。案3を考えられます。あるいは、何かいい方法がありますか?検討してください。
Vue SSRはSEOが必要で、ユーザー一人が見ている内容は全部一致しています。キャッシュと協力して、とてもいい経験になります。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。
Vueのアップグレードに従って、第一の方案はもう適用されなくなりました。第二の方案も多くの制限があります。そこで第三の方案を思い付きました。具体的に実現する方法を教えてください。
第一案
第一の案はもう適用されなくなりました。ここで詳しく説明しません。
第二の案
アイデア:cookiesをssrのcontextに注入し、apiを要求する時に読み、axiosのheaderに追加します。
1,まずserver.jsでcookiesをcontextに追加します。
const context = {
title: 'M.M.F ',
description: 'M.M.F ',
url: req.url,
cookies: req.cookies
}
renderer.renderToString(context, (err, html) => {
if (err) {
return errorHandler(err)
}
res.end(html)
})
その後、Vueはcontextをglobalに追加します。VUE_SSR_CONTEXT_u u2,appi.jsでcookiesを読みます。
import axios from 'axios'
import qs from 'qs'
import md5 from 'md5'
import config from './config-server'
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 {
async post(url, data) {
const cookie = parseCookie(cookies)
const res = await axios({
method: 'post',
url: config.api + url,
data: qs.stringify(data),
timeout: config.timeout,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
cookie
}
})
return res
},
}
なぜこのようにすることができますか?デフォルトでは、Vueはレンダリング毎に、新しいV 8コンテキストを作成し、Windows全体を再実行します。アプリケーションコードはサーバプロセスから分離されていますので、各アクセスのユーザーコンテキストは独立しています。
しかし、[email protected]最初に、createBundeleRenderer方法のオプションに、run InNewConteetオプションを追加しました。run InNewConteetを使用します。false、bundleコードはサーバープロセスと同じglobalコンテキストで実行されます。だから、cookiesをglobalに置くことはできません。
なぜ今はそうしないですか?
私達は引き続きrunInNewContectをtrueに設定したらいいじゃないですか?もちろんいいですが、コンテキストを再作成して、全体のWindowsを実行するのはかなり高価です。
自分のブログを例にとって、これまでは5つのルートコンポーネントしか描画していませんでした。loadtestのrpsは50ぐらいありましたが、その後、バックグラウンドの12つのルートコンポーネントをSSRに加えた後、rpsは直接桁を下げました。
だから今の第三の案が現れました。
第三の案
考え方:CookiesをパラメータとしてコンポーネントのasyncDataに注入し、パラメータを伝える方法で、cookiesをapiに伝えます。この方法は厄介だと言わざるを得ませんが、これは個人で考えられるより良い方法です。
ステップ1:
それともserver.jsでcookiesをcontextに注入しますか?
const context = {
title: 'M.M.F ',
url: req.url,
cookies: req.cookies,
}
renderer.renderToString(context, (err, html) => {
if (err) {
return handleError(err)
}
res.end(html)
})
ステップ2:entry-server.jsで、cookiesをパラメータとしてasyncDataに送る方法
Promise.all(matchedComponents.map(({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にあげます。
export default {
name: 'frontend-index',
async asyncData({store, route, cookies}, config = { page: 1}) {
config.cookies = cookies
await store.dispatch('frontend/article/getArticleList', config)
}
// .....
}
ステップ4:Vuexでcookiesをパラメータとしてapiにあげます。
import api from '~api'
const state = () => ({
lists: {
data: [],
hasNext: 0,
page: 1,
path: ''
},
})
const actions = {
async ['getArticleList']({commit, state}, config) {
// vuex
if (state.lists.data.length > 0 && config.path === state.lists.path && config.page === 1) {
return
}
let cookies
if (config.cookies) {
cookies = config.cookies
delete config.cookies
}
const { data: { data, code} } = await api.get('frontend/article/list', {...config, cache: true}, cookies)
if (data && code === 200) {
commit('receiveArticleList', {
...config,
...data,
})
}
},
}
const mutations = {
['receiveArticleList'](state, {list, hasNext, hasPrev, page, path}) {
if (page === 1) {
list = [].concat(list)
} else {
list = state.lists.data.concat(list)
}
state.lists = {
data: list, hasNext, hasPrev, page, path
}
},
}
const getters = {
}
export default {
namespaced: true,
state,
actions,
mutations,
getters
}
ここで注意してください。stateは必ず関数で値を返してstateを初期化します。そうでないと、すべてのユーザがstateを共有することになります。ステップ5:
apiの中でcookiesを受け取って、そしてaxiosのheadersの中に加えます。
import axios from 'axios'
import qs from 'qs'
import config from './config-server'
const parseCookie = cookies => {
let cookie = ''
Object.keys(cookies).forEach(item => {
cookie+= item + '=' + cookies[item] + '; '
})
return cookie
}
export default {
get(url, data, cookies = {}) {
const cookie = parseCookie(cookies)
return axios({
method: 'get',
url: config.api + url,
data: qs.stringify(data),
timeout: config.timeout,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
cookie
}
})
},
}
第四の案ステップ1:
それともserver.jsでcookiesをcontextに注入しますか?
const context = {
title: 'M.M.F ',
url: req.url,
cookies: req.cookies,
}
renderer.renderToString(context, (err, html) => {
if (err) {
return handleError(err)
}
res.end(html)
})
ステップ2:entry-server.jsで、cookiesをパラメータとしてapi.set Cookiesに送る方法は、appi.set Cookiesは何ですか?
api.setCookies(context.cookies) //
Promise.all(matchedComponents.map(({asyncData}) => asyncData && asyncData({
store,
route: router.currentRoute,
cookies: context.cookies,
isServer: true,
isClient: false
}))).then(() => {
// ...
}
ステップ3:appi.jsを書き換える
import axios from 'axios'
import qs from 'qs'
import config from './config-server'
const parseCookie = cookies => {
let cookie = ''
Object.keys(cookies).forEach(item => {
cookie+= item + '=' + cookies[item] + '; '
})
return cookie
}
export default {
api: null,
cookies: {},
setCookies(value) {
value = value || {}
this.cookies = value
this.api = axios.create({
baseURL: config.api,
headers: {
'X-Requested-With': 'XMLHttpRequest',
cookie: parseCookie(value)
},
timeout: config.timeout,
})
},
post(url, data) {
if (!this.api) this.setCookies()
return this.api({
method: 'post',
url,
data: qs.stringify(data),
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
}
}).then(res => {
return res
})
},
get(url, params) {
if (!this.api) this.setCookies()
return this.api({
method: 'get',
url,
params,
}).then(res => {
return res
})
}
}
ステップ4:ステップ4がないので、直接にアプリを導入して呼び出してもいいです。
もしaxiosを再パッケージしなかったら、第五段階を省略して、直接第四部でaxiosにcookiesを渡してもいいです。
シナリオ2の具体例:https://github.com/lincenying/mmf-blog-vue2-ssr
シナリオ3の具体例:https://github.com/lincenying/mmf-blog-vue2-pwa-ssr
シナリオ4の具体例:https://github.com/lincenying/mmf-blog-vue2-pwa-ssr
以上のように、プロジェクトが大きくないなら、直接案を使いましょう。プロジェクトは多くのページがあります。そして、ほとんどのページはユーザーごとに同じです。案3を考えられます。あるいは、何かいい方法がありますか?検討してください。
Vue SSRはSEOが必要で、ユーザー一人が見ている内容は全部一致しています。キャッシュと協力して、とてもいい経験になります。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。