diff --git a/lib/module.js b/lib/module.js index 8c7dd1b..e1a1c0f 100755 --- a/lib/module.js +++ b/lib/module.js @@ -59,6 +59,7 @@ function axiosModule (_moduleOptions) { progress: true, proxyHeaders: true, proxyHeadersIgnore: ['accept', 'host', 'cf-ray', 'cf-connecting-ip', 'content-length', 'content-md5', 'content-type'], + proxyCookies: true, proxy: false, retry: false, https, diff --git a/lib/plugin.js b/lib/plugin.js index a421b43..bcbdfe1 100644 --- a/lib/plugin.js +++ b/lib/plugin.js @@ -1,6 +1,7 @@ import Axios from 'axios' import defu from 'defu' <% if (options.retry) { %>import axiosRetry from 'axios-retry'<% } %> +<% if (options.proxyCookies) { %>import { parse as parseCookies } from 'cookie'<% } %> const $nuxt = typeof window !== 'undefined' && window['$<%= options.globalName %>'] @@ -179,6 +180,68 @@ const setupProgress = (axios) => { axios.defaults.onDownloadProgress = onProgress }<% } %> +<% if (options.proxyCookies) { %> +const proxyCookies = (ctx, axios, response) => { + const parseSetCookies = cookies => { + return cookies + .map(cookie => cookie.split(';')[0]) + .reduce((obj, cookie) => ({ + ...obj, + ...parseCookies(cookie) + }), {}) + } + + const serializeCookies = cookies => { + return Object + .entries(cookies) + .map(([name, value]) => `${name}=${encodeURIComponent(value)}`) + .join('; ') + } + + const mergeSetCookies = (oldCookies, newCookies) => { + const cookies = new Map() + + const add = setCookie => { + const cookie = setCookie.split(';')[0] + const name = Object.keys(parseCookies(cookie))[0] + + cookies.set(name, cookie) + } + + oldCookies.forEach(add) + newCookies.forEach(add) + + return [...cookies.values()] + } + + const arrayify = obj => Array.isArray(obj) ? obj : [obj] + + if (response.headers['set-cookie']) { + const setCookies = arrayify(response.headers['set-cookie']) + + // Combine the cookies set on axios with the new cookies and serialize them + const cookie = serializeCookies({ + ...parseCookies(axios.defaults.headers.common.cookie), + ...parseSetCookies(setCookies) + }) + + axios.defaults.headers.common.cookie = cookie + + // If the res already has a Set-Cookie header it should be merged + if (ctx.res.getHeader('Set-Cookie')) { + const newCookies = mergeSetCookies( + arrayify(ctx.res.getHeader('Set-Cookie')), + setCookies + ) + + ctx.res.setHeader('Set-Cookie', newCookies) + } else { + ctx.res.setHeader('Set-Cookie', setCookies) + } + } +} +<% } %> + export default (ctx, inject) => { // baseURL const baseURL = process.browser @@ -213,6 +276,15 @@ export default (ctx, inject) => { const axios = createAxiosInstance(axiosOptions) + <% if (options.proxyCookies) { %> + // Proxy cookies + if (process.server) { + axios.onResponse(response => { + proxyCookies(ctx, axios, response) + }) + } + <% } %> + // Inject axios to the context as $axios ctx.$axios = axios inject('axios', axios) diff --git a/package.json b/package.json index d5eed33..307f377 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "axios": "^0.19.2", "axios-retry": "^3.1.8", "consola": "^2.11.3", + "cookie": "^0.4.1", "defu": "^2.0.2" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 9bad7eb..c03e218 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3289,6 +3289,11 @@ cookie@^0.3.1: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= +cookie@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== + copy-concurrently@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"