Maison  >  Article  >  interface Web  >  Analyser les problématiques liées aux Cookies de Vue SSR

Analyser les problématiques liées aux Cookies de Vue SSR

不言
不言original
2018-06-30 17:09:491723parcourir

Cet article présente principalement le problème des cookies de Vue SSR. Le contenu est assez bon, je vais le partager avec vous maintenant et le donner comme référence.

Une fois qu'un site Web implique plusieurs utilisateurs, il est difficile d'échapper aux cookies. Les cookies de Vue SSR sont vraiment un gros problème. Depuis le début de SSR jusqu'à maintenant, j'en ai trouvé un total de 3. options, depuis la première injection de cookies dans l'état, jusqu'à l'injection de cookies dans global, jusqu'à l'injection actuelle de cookies dans la méthode asyncData du composant.

Avec la mise à niveau de Vue, la première option a été Elle n'est plus applicable. La deuxième option présente également de nombreuses limites, j'ai donc pensé à la troisième option. Parlons de la méthode de mise en œuvre spécifique :

La première option

. La première solution n'est plus applicable et ne sera pas abordée en détail ici

La deuxième solution

Idée : Injecter des cookies dans un contexte ssr, puis lire lors de la demande de l'API, puis ajoutez-la à l'en-tête d'axios

1. Ajoutez d'abord les cookies au contexte dans 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)
})

.

Après cela, Vue ajoutera du contexte à global.__VUE_SSR_CONTEXT__

2, lisez les cookies dans 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
 },
}

Pourquoi cela peut-il être fait ?

Par défaut, Vue pour chaque rendu, le moteur de rendu du bundle créera un nouveau contexte V8 et le réexécutera dans son intégralité. Le code de l'application est isolé du processus serveur, donc chaque contexte utilisateur accédé est indépendant et ne s'affectera pas les uns les autres.

Mais à partir de Vue@2.3.0, runInNewContext est ajouté dans les options de l'option de méthode createBundleRenderer , utilisez runInNewContext : false, le code du bundle s'exécutera dans le même contexte global que le processus serveur, nous ne pouvons donc plus mettre de cookies en global, car cela amènera tous les utilisateurs à partager les mêmes cookies.

Pourquoi ne pas faire cela maintenant ?

Ensuite, continuons à définir runInNewContext sur true, n'est-ce pas bien sûr possible, mais recréant le contexte et exécutant l'intégralité du bundle ? est encore assez cher, surtout lorsque l'application est très volumineuse

En prenant mon propre blog comme exemple, je n'ai rendu que 5 composants de routage auparavant, et le rps du test de charge était d'environ 50, mais plus tard j'ai ajouté 12 composants de routage. composants en arrière-plan. Après avoir ajouté SSR, le rps est tombé directement à un chiffre...

La troisième solution est donc apparue

La troisième solution

Idée : injectez des cookies en tant que paramètres dans la méthode asyncData du composant, puis transmettez les cookies à l'API en passant des paramètres. Je dois dire que cette méthode est très gênante, mais c'est la meilleure chose à laquelle je puisse penser. de.Méthode

Étape 1 :

Toujours dans server.js, injecter des cookies dans le contexte

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)
})

Étape 2 :

Dans Entry-server.js, transmettez les cookies en tant que paramètres à la méthode 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)

Étape 3 :

Dans le composant, transmettez les cookies comme paramètres aux actions Vuex

export default {
 name: 'frontend-index',
 async asyncData({store, route, cookies}, config = { page: 1}) {
  config.cookies = cookies
  await store.dispatch('frontend/article/getArticleList', config)
 }
 // .....
}

Étape 4 :

Dans Vuex Pass, les cookies comme paramètres à l'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
}

Assurez-vous de noter ici que l'état doit être initialisé avec la valeur de retour de la fonction, sinon tous les utilisateurs passeront à l'état partagé

Étape 5 :

Recevez les cookies dans l'API et ajoutez-les aux en-têtes d'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
   }
  })
 },
}

La quatrième option

Étape 1 :

Toujours dans server.js, injecter des cookies dans le contexte

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)
})

Étape 2 :

Dans Entry-server.js, transmettez les cookies en tant que paramètres à la méthode api.setCookies suivi de

api.setCookies(context.cookies) // 这一句
Promise.all(matchedComponents.map(({asyncData}) => asyncData && asyncData({
 store,
 route: router.currentRoute,
 cookies: context.cookies,
 isServer: true,
 isClient: false
}))).then(() => {
 // ...
}
<.>

Étape 3 :

Réécrire api.js

import axios from &#39;axios&#39;
import qs from &#39;qs&#39;
import config from &#39;./config-server&#39;

const parseCookie = cookies => {
  let cookie = &#39;&#39;
  Object.keys(cookies).forEach(item => {
    cookie+= item + &#39;=&#39; + cookies[item] + &#39;; &#39;
  })
  return cookie
}

export default {
  api: null,
  cookies: {},
  setCookies(value) {
    value = value || {}
    this.cookies = value
    this.api = axios.create({
      baseURL: config.api,
      headers: {
        &#39;X-Requested-With&#39;: &#39;XMLHttpRequest&#39;,
        cookie: parseCookie(value)
      },
      timeout: config.timeout,
    })
  },
  post(url, data) {
    if (!this.api) this.setCookies()
    return this.api({
      method: &#39;post&#39;,
      url,
      data: qs.stringify(data),
      headers: {
        &#39;Content-Type&#39;: &#39;application/x-www-form-urlencoded; charset=UTF-8&#39;,
      }
    }).then(res => {
      return res
    })
  },
  get(url, params) {
    if (!this.api) this.setCookies()
    return this.api({
      method: &#39;get&#39;,
      url,
      params,
    }).then(res => {
      return res
    })
  }
}

Étape 4 :

Il n'y a pas d'étape 4, introduisez simplement l'appel api directement

Si vous n'avez pas reconditionné axios, vous pouvez également omettre la cinquième étape et passer directement à la quatrième étape Donnez simplement les cookies à axios

Exemple spécifique de l'option 2 : https://github.com/lincenying/mmf-blog-vue2-ssr

Exemple spécifique de l'option 3 : https:// github.com/lincenying/mmf-blog -vue2-pwa-ssr

Option 4 Exemple spécifique : https://github.com/lincenying/mmf-blog-vue2-pwa-ssr

Pour résumer, si votre projet est pas grand, vous devriez simplement utiliser l'option 2. Le projet comporte de nombreuses pages, et la plupart des pages sont les mêmes pour chaque utilisateur. Vous pouvez envisager l'option 3. Si vous avez une meilleure méthode, veuillez en discuter

Vue SSR nécessite du SEO, et le contenu vu par chaque utilisateur est cohérent Avec la mise en cache, ce sera une très bonne expérience...


C'est tout pour cet article. L'intégralité du contenu, je l'espère. sera utile à l'étude de chacun. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois !

Recommandations associées :

À propos de la méthode de mise en cache des données API de Vue2 SSR


Le projet vue2.0 implémente la méthode de saut de routage présentation


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn