This article mainly introduces the Cookies issue of Vue SSR. The content is quite good. I will share it with you now and give it as a reference.
Once a website involves multiple users, it is difficult to escape from cookies. The cookies of Vue SSR are really a big problem. From the beginning of playing SSR to now, I have come up with a total of 3 solutions, from the earliest one to inject Cookies into the state, to the first one to inject Cookies into global, to the current one to inject Cookies into the asyncData method of the component.
With the upgrade of Vue, the first solution has been It is no longer applicable. The second option also has many limitations, so I thought of the third option. Let’s talk about the specific implementation method:
The first option
The first solution is no longer applicable, I won’t go into details here
The second solution
Idea: Inject cookies into ssr context, then read it when requesting the api, and then append it to the header of axios
1, first add cookies to the context in server.js
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) })
After that, Vue will add context to global.__VUE_SSR_CONTEXT__
2, and read cookies in api.js
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 }, }
Why can this be done?
By default, Vue for each rendering, the bundle renderer will create a new V8 context and re-execute the entire bundle. The application code is isolated from the server process, so each accessed user context is independent and will not affect each other.
But starting from Vue@2.3.0, runInNewContext is added to the options of the createBundleRenderer method. option, use runInNewContext: false, the bundle code will run in the same global context as the server process, so we can no longer put cookies in global, because this will cause all users to share the same cookies.
Why not do this now?
Then let’s continue setting runInNewContext to true, wouldn’t it? Of course it is possible, but re-creating the context and executing the entire bundle is still quite expensive , especially when the application is very large.
Take my own blog as an example. Before, I only rendered 5 routing components, and the rps of loadtest was about 50. But later, I added 12 routing components in the background. After adding SSR, the rps dropped directly to single digits...
So the third solution appeared
The third solution
Idea: Inject Cookies as parameters into the asyncData method of the component, and then use the method of passing parameters to pass the cookies to the API. I have to say that this method is very troublesome, but this is the better thing I can think of. Method
Step 1:
Still in server.js, inject cookies into 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) })
Step 2 :
In entry-server.js, pass cookies as parameters to the asyncData method
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)
Step 3:
In the component, use cookies as parameters for 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) } // ..... }
Step 4:
Use cookies as parameters in Vuex For 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 }
, you must pay attention here. The state must be initialized with the function return value, otherwise it will cause all users to share the state
Step 5:
Receive cookies in the api and add them to the headers of axios
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 } }) }, }
The fourth option
Step 1:
Still in server.js, inject cookies into 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) })
Step 2 :
In entry-server.js, pass cookies as parameters to the api.setCookies method. What is api.setCookies followed by
api.setCookies(context.cookies) // 这一句 Promise.all(matchedComponents.map(({asyncData}) => asyncData && asyncData({ store, route: router.currentRoute, cookies: context.cookies, isServer: true, isClient: false }))).then(() => { // ... }
Step 3:
Rewrite api.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 }) } }
Step 4:
No more step 4 , just introduce the api call directly
If you have not re-packaged axios, you can also omit the fifth step and directly give the cookies to axios in the fourth part
Option 2 is specific Example: https://github.com/lincenying/mmf-blog-vue2-ssr
Option 3 Specific example: https://github.com/lincenying/mmf-blog-vue2-pwa-ssr
Specific example of option 4: https://github.com/lincenying/mmf-blog-vue2-pwa-ssr
In summary, if your project is not big, just use option 2. , the project has many pages, and most of the pages are the same for every user, you can consider option 3, or if you have any better methods, welcome to discuss
Vue SSR needs SEO, and every user The content you see is consistent. With caching, it will be a very good experience...
The above is the entire content of this article. I hope it will be helpful to everyone's learning. More related Please pay attention to the PHP Chinese website for content!
Related recommendations:
About the method of Vue2 SSR caching Api data
vue2.0 project implements routing jump Method introduction
The above is the detailed content of Analyze issues related to Cookies of Vue SSR. For more information, please follow other related articles on the PHP Chinese website!