diff --git a/index.d.ts b/index.d.ts index ad014ccd4e..8a2f126dca 100644 --- a/index.d.ts +++ b/index.d.ts @@ -277,6 +277,10 @@ export interface AxiosProgressEvent { type Milliseconds = number; +type AxiosAdapterName = 'xhr' | 'http' | string; + +type AxiosAdapterConfig = AxiosAdapter | AxiosAdapterName; + export interface AxiosRequestConfig { url?: string; method?: Method | string; @@ -290,7 +294,7 @@ export interface AxiosRequestConfig { timeout?: Milliseconds; timeoutErrorMessage?: string; withCredentials?: boolean; - adapter?: AxiosAdapter; + adapter?: AxiosAdapterConfig | AxiosAdapterConfig[]; auth?: AxiosBasicCredentials; responseType?: ResponseType; responseEncoding?: responseEncoding | string; diff --git a/lib/adapters/adapters.js b/lib/adapters/adapters.js new file mode 100644 index 0000000000..e31fca1203 --- /dev/null +++ b/lib/adapters/adapters.js @@ -0,0 +1,59 @@ +import utils from '../utils.js'; +import httpAdapter from './http.js'; +import xhrAdapter from './xhr.js'; +import AxiosError from "../core/AxiosError.js"; + +const knownAdapters = { + http: httpAdapter, + xhr: xhrAdapter +} + +utils.forEach(knownAdapters, (fn, value) => { + if(fn) { + try { + Object.defineProperty(fn, 'name', {value}); + } catch (e) { + // eslint-disable-next-line no-empty + } + Object.defineProperty(fn, 'adapterName', {value}); + } +}); + +export default { + getAdapter: (adapters) => { + adapters = utils.isArray(adapters) ? adapters : [adapters]; + + const {length} = adapters; + let nameOrAdapter; + let adapter; + + for (let i = 0; i < length; i++) { + nameOrAdapter = adapters[i]; + if((adapter = utils.isString(nameOrAdapter) ? knownAdapters[nameOrAdapter.toLowerCase()] : nameOrAdapter)) { + break; + } + } + + if (!adapter) { + if (adapter === false) { + throw new AxiosError( + `Adapter ${nameOrAdapter} is not supported by the environment`, + 'ERR_NOT_SUPPORT' + ); + } + + throw new Error( + utils.hasOwnProp(knownAdapters, nameOrAdapter) ? + `Adapter '${nameOrAdapter}' is not available in the build` : + `Unknown adapter '${nameOrAdapter}'` + ); + } + + if (!utils.isFunction(adapter)) { + throw new TypeError('adapter is not a function'); + } + + return adapter; + }, + adapters: knownAdapters +} diff --git a/lib/adapters/http.js b/lib/adapters/http.js index 5dbd97c8e9..10c24ce727 100755 --- a/lib/adapters/http.js +++ b/lib/adapters/http.js @@ -100,8 +100,10 @@ function setProxy(options, configProxy, location) { }; } +const isHttpAdapterSupported = typeof process !== 'undefined' && utils.kindOf(process) === 'process'; + /*eslint consistent-return:0*/ -export default function httpAdapter(config) { +export default isHttpAdapterSupported && function httpAdapter(config) { return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) { let data = config.data; const responseType = config.responseType; diff --git a/lib/adapters/index.js b/lib/adapters/index.js deleted file mode 100644 index 02ab126642..0000000000 --- a/lib/adapters/index.js +++ /dev/null @@ -1,33 +0,0 @@ -import utils from '../utils.js'; -import httpAdapter from './http.js'; -import xhrAdapter from './xhr.js'; - -const adapters = { - http: httpAdapter, - xhr: xhrAdapter -} - -export default { - getAdapter: (nameOrAdapter) => { - if(utils.isString(nameOrAdapter)){ - const adapter = adapters[nameOrAdapter]; - - if (!nameOrAdapter) { - throw Error( - utils.hasOwnProp(nameOrAdapter) ? - `Adapter '${nameOrAdapter}' is not available in the build` : - `Can not resolve adapter '${nameOrAdapter}'` - ); - } - - return adapter - } - - if (!utils.isFunction(nameOrAdapter)) { - throw new TypeError('adapter is not a function'); - } - - return nameOrAdapter; - }, - adapters -} diff --git a/lib/adapters/xhr.js b/lib/adapters/xhr.js index 54bc6619ae..f5ef6460bb 100644 --- a/lib/adapters/xhr.js +++ b/lib/adapters/xhr.js @@ -43,7 +43,9 @@ function progressEventReducer(listener, isDownloadStream) { }; } -export default function xhrAdapter(config) { +const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined'; + +export default isXHRAdapterSupported && function (config) { return new Promise(function dispatchXhrRequest(resolve, reject) { let requestData = config.data; const requestHeaders = AxiosHeaders.from(config.headers).normalize(); diff --git a/lib/core/dispatchRequest.js b/lib/core/dispatchRequest.js index dfe4c41d66..fe0fa3dd13 100644 --- a/lib/core/dispatchRequest.js +++ b/lib/core/dispatchRequest.js @@ -5,6 +5,7 @@ import isCancel from '../cancel/isCancel.js'; import defaults from '../defaults/index.js'; import CanceledError from '../cancel/CanceledError.js'; import AxiosHeaders from '../core/AxiosHeaders.js'; +import adapters from "../adapters/adapters.js"; /** * Throws a `CanceledError` if cancellation has been requested. @@ -45,7 +46,7 @@ export default function dispatchRequest(config) { config.headers.setContentType('application/x-www-form-urlencoded', false); } - const adapter = config.adapter || defaults.adapter; + const adapter = adapters.getAdapter(config.adapter || defaults.adapter); return adapter(config).then(function onAdapterResolution(response) { throwIfCancellationRequested(config); diff --git a/lib/defaults/index.js b/lib/defaults/index.js index b68ab0eae6..0b4760219b 100644 --- a/lib/defaults/index.js +++ b/lib/defaults/index.js @@ -7,30 +7,11 @@ import toFormData from '../helpers/toFormData.js'; import toURLEncodedForm from '../helpers/toURLEncodedForm.js'; import platform from '../platform/index.js'; import formDataToJSON from '../helpers/formDataToJSON.js'; -import adapters from '../adapters/index.js'; const DEFAULT_CONTENT_TYPE = { 'Content-Type': undefined }; -/** - * If the browser has an XMLHttpRequest object, use the XHR adapter, otherwise use the HTTP - * adapter - * - * @returns {Function} - */ -function getDefaultAdapter() { - let adapter; - if (typeof XMLHttpRequest !== 'undefined') { - // For browsers use XHR adapter - adapter = adapters.getAdapter('xhr'); - } else if (typeof process !== 'undefined' && utils.kindOf(process) === 'process') { - // For node use HTTP adapter - adapter = adapters.getAdapter('http'); - } - return adapter; -} - /** * It takes a string, tries to parse it, and if it fails, it returns the stringified version * of the input @@ -60,7 +41,7 @@ const defaults = { transitional: transitionalDefaults, - adapter: getDefaultAdapter(), + adapter: ['xhr', 'http'], transformRequest: [function transformRequest(data, headers) { const contentType = headers.getContentType() || ''; diff --git a/package.json b/package.json index e3c56ab7a9..e0f1e15f29 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "url-search-params": "^0.10.0" }, "browser": { - "./lib/adapters/http.js": "./lib/adapters/xhr.js", + "./lib/adapters/http.js": "./lib/helpers/null.js", "./lib/platform/node/index.js": "./lib/platform/browser/index.js" }, "jsdelivr": "dist/axios.min.js", @@ -138,4 +138,4 @@ "Daniel Lopretto (https://github.com/timemachine3030)" ], "sideEffects": false -} \ No newline at end of file +} diff --git a/test/typescript/axios.ts b/test/typescript/axios.ts index 5fc17b3843..1be0557e9a 100644 --- a/test/typescript/axios.ts +++ b/test/typescript/axios.ts @@ -497,3 +497,17 @@ axios.get('/user', { console.log(e.rate); } }); + +// adapters + +axios.get('/user', { + adapter: 'xhr' +}); + +axios.get('/user', { + adapter: 'http' +}); + +axios.get('/user', { + adapter: ['xhr', 'http'] +});