You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
5.4 KiB
205 lines
5.4 KiB
import Axios from 'axios' |
|
import defu from 'defu' |
|
|
|
// Axios.prototype cannot be modified |
|
const axiosExtra = { |
|
setBaseURL (baseURL) { |
|
this.defaults.baseURL = baseURL |
|
}, |
|
setHeader (name, value, scopes = 'common') { |
|
for (const scope of Array.isArray(scopes) ? scopes : [ scopes ]) { |
|
if (!value) { |
|
delete this.defaults.headers[scope][name]; |
|
continue |
|
} |
|
this.defaults.headers[scope][name] = value |
|
} |
|
}, |
|
setToken (token, type, scopes = 'common') { |
|
const value = !token ? null : (type ? type + ' ' : '') + token |
|
this.setHeader('Authorization', value, scopes) |
|
}, |
|
onRequest(fn) { |
|
this.interceptors.request.use(config => fn(config) || config) |
|
}, |
|
onResponse(fn) { |
|
this.interceptors.response.use(response => fn(response) || response) |
|
}, |
|
onRequestError(fn) { |
|
this.interceptors.request.use(undefined, error => fn(error) || Promise.reject(error)) |
|
}, |
|
onResponseError(fn) { |
|
this.interceptors.response.use(undefined, error => fn(error) || Promise.reject(error)) |
|
}, |
|
onError(fn) { |
|
this.onRequestError(fn) |
|
this.onResponseError(fn) |
|
}, |
|
create(options) { |
|
return createAxiosInstance(defu(options, this.defaults)) |
|
} |
|
} |
|
|
|
// Request helpers ($get, $post, ...) |
|
for (const method of ['request', 'delete', 'get', 'head', 'options', 'post', 'put', 'patch']) { |
|
axiosExtra['$' + method] = function () { return this[method].apply(this, arguments).then(res => res && res.data) } |
|
} |
|
|
|
const extendAxiosInstance = axios => { |
|
for (const key in axiosExtra) { |
|
axios[key] = axiosExtra[key].bind(axios) |
|
} |
|
} |
|
|
|
const createAxiosInstance = axiosOptions => { |
|
// Create new axios instance |
|
const axios = Axios.create(axiosOptions) |
|
axios.CancelToken = Axios.CancelToken |
|
axios.isCancel = Axios.isCancel |
|
|
|
// Extend axios proto |
|
extendAxiosInstance(axios) |
|
|
|
// Intercept to apply default headers |
|
axios.onRequest((config) => { |
|
config.headers = { ...axios.defaults.headers.common, ...config.headers } |
|
}) |
|
|
|
// Setup interceptors |
|
|
|
setupCredentialsInterceptor(axios) |
|
setupProgress(axios) |
|
|
|
return axios |
|
} |
|
|
|
const setupCredentialsInterceptor = axios => { |
|
// Send credentials only to relative and API Backend requests |
|
axios.onRequest(config => { |
|
if (config.withCredentials === undefined) { |
|
if (!/^https?:\/\//i.test(config.url) || config.url.indexOf(config.baseURL) === 0) { |
|
config.withCredentials = true |
|
} |
|
} |
|
}) |
|
} |
|
|
|
const setupProgress = (axios) => { |
|
if (process.server) { |
|
return |
|
} |
|
|
|
// A noop loading inteterface for when $nuxt is not yet ready |
|
const noopLoading = { |
|
finish: () => { }, |
|
start: () => { }, |
|
fail: () => { }, |
|
set: () => { } |
|
} |
|
|
|
const $loading = () => { |
|
const $nuxt = typeof window !== 'undefined' && window['$nuxt'] |
|
return ($nuxt && $nuxt.$loading && $nuxt.$loading.set) ? $nuxt.$loading : noopLoading |
|
} |
|
|
|
let currentRequests = 0 |
|
|
|
axios.onRequest(config => { |
|
if (config && config.progress === false) { |
|
return |
|
} |
|
|
|
currentRequests++ |
|
}) |
|
|
|
axios.onResponse(response => { |
|
if (response && response.config && response.config.progress === false) { |
|
return |
|
} |
|
|
|
currentRequests-- |
|
if (currentRequests <= 0) { |
|
currentRequests = 0 |
|
$loading().finish() |
|
} |
|
}) |
|
|
|
axios.onError(error => { |
|
if (error && error.config && error.config.progress === false) { |
|
return |
|
} |
|
|
|
currentRequests-- |
|
|
|
if (Axios.isCancel(error)) { |
|
if (currentRequests <= 0) { |
|
currentRequests = 0 |
|
$loading().finish() |
|
} |
|
return |
|
} |
|
|
|
$loading().fail() |
|
$loading().finish() |
|
}) |
|
|
|
const onProgress = e => { |
|
if (!currentRequests || !e.total) { |
|
return |
|
} |
|
const progress = ((e.loaded * 100) / (e.total * currentRequests)) |
|
$loading().set(Math.min(100, progress)) |
|
} |
|
|
|
axios.defaults.onUploadProgress = onProgress |
|
axios.defaults.onDownloadProgress = onProgress |
|
} |
|
|
|
export default (ctx, inject) => { |
|
// runtimeConfig |
|
const runtimeConfig = ctx.$config && ctx.$config.axios || {} |
|
// baseURL |
|
const baseURL = process.browser |
|
? (runtimeConfig.browserBaseURL || runtimeConfig.browserBaseUrl || runtimeConfig.baseURL || runtimeConfig.baseUrl || 'http://localhost:3000/web') |
|
: (runtimeConfig.baseURL || runtimeConfig.baseUrl || process.env._AXIOS_BASE_URL_ || 'http://localhost:3000/web') |
|
|
|
// Create fresh objects for all default header scopes |
|
// Axios creates only one which is shared across SSR requests! |
|
// https://github.com/mzabriskie/axios/blob/master/lib/defaults.js |
|
const headers = { |
|
"common": { |
|
"Accept": "application/json, text/plain, */*" |
|
}, |
|
"delete": {}, |
|
"get": {}, |
|
"head": {}, |
|
"post": {}, |
|
"put": {}, |
|
"patch": {} |
|
} |
|
|
|
const axiosOptions = { |
|
baseURL, |
|
headers |
|
} |
|
|
|
// Proxy SSR request headers headers |
|
if (process.server && ctx.req && ctx.req.headers) { |
|
const reqHeaders = { ...ctx.req.headers } |
|
for (const h of ["accept","cf-connecting-ip","cf-ray","content-length","content-md5","content-type","host","x-forwarded-host","x-forwarded-port","x-forwarded-proto"]) { |
|
delete reqHeaders[h] |
|
} |
|
axiosOptions.headers.common = { ...reqHeaders, ...axiosOptions.headers.common } |
|
} |
|
|
|
if (process.server) { |
|
// Don't accept brotli encoding because Node can't parse it |
|
axiosOptions.headers.common['accept-encoding'] = 'gzip, deflate' |
|
} |
|
|
|
const axios = createAxiosInstance(axiosOptions) |
|
|
|
// Inject axios to the context as $axios |
|
ctx.$axios = axios |
|
inject('axios', axios) |
|
}
|
|
|