最后說說Vue2 SSR 的 Cookies 問題
本來想前面寫點什么的, 還是算了, 直接說思路吧.
從 Vue2.3 版本后, SSR 的 cookies, 就變成一個無比麻煩的問題, 具體請訪問官網(wǎng)文檔: https://ssr.vuejs.org/zh/api.html#runinnewcontext
之前也說不少的思路, 可是都覺得不怎么好用, 雖然都能解決問題, 今天再說一種思路
因為 Vue2.3 以后, bundle 代碼將與服務(wù)器進程在同一個 global 上下文中運行, 所以不能再將 cookies 丟到 global 給 api 使用, 否則就會出現(xiàn) cookies 污染
Vue2.3 以后, 我們需要為每個請求創(chuàng)建一個新的根 Vue 實例, 同樣的, router、store 也需要, 所以, 我們的思路也在此, 將封裝后的 api 注入到這 3 個實例當(dāng)中去, 保證每個請求的 api 都是獨立, 那么就剩一個問題, 注入到哪個實例里面去!?
api 請求用到最多的兩個地方就是: 組件和 vuex 的 actions 里, 這兩個地方都有 store 的影子, 所以, 注入到 store 中, 毫無疑問是最好的
那么下面就來操作下:
1. 修改 api, 讓 api 文件導(dǎo)出一個工廠函數(shù)
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 當(dāng)參數(shù)傳進工廠函數(shù), 給 axios 使用
示例文件1: src/api/index-server.js
示例文件2: src/api/index-client.js
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`)
}
})
// 前后代碼略
示例文件: server.js
3. 修改服務(wù)端入口文件
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里已經(jīng)帶有cookies了
// 創(chuàng)建一個新的api實例, 并把cookies傳進去
// 同時注入store和根狀態(tài)中
// 注入 store 中, 可以方便在組件中用
// 注入 根狀態(tài)中, 可以方便在 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)
})
}
示例文件: src/entry-server.js
4. 修改客戶端入口文件
import api from '~api'
// 前后代碼略
const { app, router, store } = createApp()
if (window.__INITIAL_STATE__) {
store.replaceState(window.__INITIAL_STATE__)
// 客戶端就沒必要用工廠函數(shù)了, 用也可以, 但是需注意, api里的屬性必須和服務(wù)端的保持一致
store.$api = store.state.$api = api
}
// 前后代碼略
示例文件: src/entry-client.js
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
})
}
}
}
示例文件: src/store/modules/frontend-article.js
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)
}
}
}
示例文件: src/components/frontend-comment.vue
至此, 全文結(jié)束, 完整代碼, 請參考: https://github.com/lincenying/mmf-blog-vue2-pwa-ssr
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue本地模擬服務(wù)器請求mock數(shù)據(jù)的方法詳解
這篇文章主要給大家介紹了關(guān)于vue本地模擬服務(wù)器請求mock數(shù)據(jù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-03-03
Vue3+TypeScript埋點方面的應(yīng)用實踐
本文詳細闡述了如何在Vue3中使用TypeScript實現(xiàn)埋點功能,包括全局注冊$track插件、Mixin實現(xiàn)全局埋點等,隨著Vue3的逐漸普及,在實際工作中采用Vue3+TypeScript實現(xiàn)埋點將會變得越來越流行2023-08-08
Vue的filters(本地)或filter(全局)過濾常用數(shù)據(jù)類型解析
這篇文章主要介紹了Vue的filters(本地)或filter(全局)過濾常用數(shù)據(jù)類型,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07

