当前位置: 移动技术网 > IT编程>脚本编程>vue.js > 最后说说Vue2 SSR 的 Cookies 问题

最后说说Vue2 SSR 的 Cookies 问题

2018年08月10日  | 移动技术网IT编程  | 我要评论

阿哲和天佑怎么了,彩色留言,滕县保卫战幸存者

本来想前面写点什么的, 还是算了, 直接说思路吧.

从 vue2.3 版本后, ssr 的 cookies, 就变成一个无比麻烦的问题, 具体请访问官网文档:

之前也说不少的思路, 可是都觉得不怎么好用, 虽然都能解决问题, 今天再说一种思路

因为 vue2.3 以后, bundle 代码将与服务器进程在同一个 global 上下文中运行, 所以不能再将 cookies 丢到 global 给 api 使用, 否则就会出现 cookies 污染

vue2.3 以后, 我们需要为每个请求创建一个新的根 vue 实例, 同样的, router、store 也需要, 所以, 我们的思路也在此, 将封装后的 api 注入到这 3 个实例当中去, 保证每个请求的 api 都是独立, 那么就剩一个问题, 注入到哪个实例里面去!?

api 请求用到最多的两个地方就是: 组件和 vuex 的 actions 里, 这两个地方都有 store 的影子, 所以, 注入到 store 中, 毫无疑问是最好的

那么下面就来操作下:

1. 修改 api, 让 api 文件导出一个工厂函数

import axios from 'axios'
import qs from 'qs'
import md5 from 'md5'
import config from './config-server'

const parsecookie = cookies => {
  let cookie = ''
  object.keys(cookies).foreach(item => {
    cookie += item + '=' + cookies[item] + '; '
  })
  return cookie
}

export const api = cookies => {
  return {
    api: axios.create({
      baseurl: config.api,
      headers: {
        'x-requested-with': 'xmlhttprequest',
        cookie: parsecookie(cookies)
      },
      timeout: config.timeout
    }),
    post(url, data) {
      return this.api({
        method: 'post',
        url,
        data: qs.stringify(data),
        headers: {
          'content-type': 'application/x-www-form-urlencoded; charset=utf-8'
        }
      })
    },
    async get(url, params) {
      return this.api({
        method: 'get',
        url,
        params
      })
    }
  }
}

把 cookies 当参数传进工厂函数, 给 axios 使用

示例文件1:

示例文件2:

2. 修改 server.js 文件, 将 cookies 注入 renderer 的 上下文中

// 前后代码略
  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)
    if (!isprod) {
      console.log(`whole request: ${date.now() - s}ms`)
    }
  })
// 前后代码略

示例文件:

3. 修改服务端入口文件

import { createapp } from './app'
import { api } from '~api'
export default function(context) {
  return new promise((resolve, reject) => {
    const s = date.now()
    const { app, router, store } = createapp()
    const url = context.url
    const fullpath = router.resolve(url).route.fullpath
    if (fullpath !== url) {
      reject({ url: fullpath })
    }
    router.push(url)
    router.onready(() => {
      const matchedcomponents = router.getmatchedcomponents()
      if (!matchedcomponents.length) {
        reject({ code: 404 })
      }
      // 注意这里, 在步骤2中, context里已经带有cookies了
      // 创建一个新的api实例, 并把cookies传进去
      // 同时注入store和根状态中
      // 注入 store 中, 可以方便在组件中用
      // 注入 根状态中, 可以方便在 vuex 的 actions 中用
      store.$api = store.state.$api = api(context.cookies)
      promise.all(
        matchedcomponents.map(
          ({ asyncdata }) =>
            asyncdata &&
            asyncdata({
              store,
              route: router.currentroute,
              cookies: context.cookies,
              isserver: true,
              isclient: false
            })
        )
      )
        .then(() => {
          console.log(`data pre-fetch: ${date.now() - s}ms`)
          context.state = store.state
          context.isprod = process.env.node_env === 'production'
          resolve(app)
        })
        .catch(reject)
    }, reject)
  })
}

示例文件:

4. 修改客户端入口文件

import api from '~api'
// 前后代码略
const { app, router, store } = createapp()

if (window.__initial_state__) {
  store.replacestate(window.__initial_state__)
  // 客户端就没必要用工厂函数了, 用也可以, 但是需注意, api里的属性必须和服务端的保持一致
  store.$api = store.state.$api = api
}
// 前后代码略

示例文件:

5. 在 vuex 的 actions 中使用

const actions = {
  async ['getarticlelist'](
    {
      commit,
      state,
      rootstate: { $api } // 这里就是前面注入的api
    },
    config
  ) {
    const {
      data: { data, code }
    } = await $api.get('frontend/article/list', { ...config, cache: true })
    if (data && code === 200) {
      commit('receivearticlelist', {
        ...config,
        ...data
      })
    }
  }
}

示例文件:

6. 在组件中使用

methods: {
    async recover(id) {
      const {
        data: { code, message }
      } = await this.$store.$api.get('frontend/comment/recover', { id })
      if (code === 200) {
        this.$store.commit('global/comment/recovercomment', id)
      }
    }
}

示例文件:

至此, 全文结束, 完整代码, 请参考:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网