2
0
mirror of https://github.com/tenrok/axios.git synced 2026-06-17 19:21:29 +03:00
Files
axios/lib/core/dispatchRequest.js
T
Liuwei1125 847d89b436 fix: support URL object as config.url input (#10866)
* fix(buildURL): support URL object as input

Fixes #6546

When passing a URL object (e.g., new URL(...)) to axios methods
like axios.get(url, { params: {...} }), the buildURL function
would crash with 'url.indexOf is not a function' because it assumed
url was always a string.

This fix converts URL objects to strings before processing.

* fix: support URL object as config.url input

- Move URL object coercion from buildURL to Axios._request so that all
  downstream consumers (buildFullPath, combineURLs, adapters) see a string.
  This fixes the crash when using URL object with baseURL (combineURLs
  calls .replace() on the URL object).
- Remove the broken buildURL unit test that tested buildURL(url, null)
  without actually exercising URL coercion (buildURL early-returns when
  !params).
- Add e2e tests via the HTTP adapter for URL object with params and
  URL object without params (no crash).

* feat: note + example added under axios(url[, config]) documenting URL support

* feat: url widened to string | URL

* feat: oercion now uses config.url instanceof url

* chore: add additional test cases to improve coverage

* fix: apply suggestions from cubic review

---------

Co-authored-by: liuwei53 <liuwei53@baidu.com>
Co-authored-by: Jason Saayman <jasonsaayman@gmail.com>
2026-05-09 19:09:13 +02:00

113 lines
3.1 KiB
JavaScript

'use strict';
import transformData from './transformData.js';
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';
const { toString } = Object.prototype;
const isURL = (url) => {
if (url === null || typeof url !== 'object') {
return false;
}
const prototype = Object.getPrototypeOf(url);
return prototype !== null && prototype !== Object.prototype && toString.call(url) === '[object URL]';
};
const normalizeURL = (url) => (isURL(url) ? url.toString() : url);
function normalizeConfigURL(config) {
if (isURL(config.url)) {
config.url = normalizeURL(config.url);
}
}
/**
* Throws a `CanceledError` if cancellation has been requested.
*
* @param {Object} config The config that is to be used for the request
*
* @returns {void}
*/
function throwIfCancellationRequested(config) {
if (config.cancelToken) {
config.cancelToken.throwIfRequested();
}
if (config.signal && config.signal.aborted) {
throw new CanceledError(null, config);
}
}
/**
* Dispatch a request to the server using the configured adapter.
*
* @param {object} config The config that is to be used for the request
*
* @returns {Promise} The Promise to be fulfilled
*/
export default function dispatchRequest(config) {
normalizeConfigURL(config);
throwIfCancellationRequested(config);
config.headers = AxiosHeaders.from(config.headers);
// Transform request data
config.data = transformData.call(config, config.transformRequest);
if (['post', 'put', 'patch'].indexOf(config.method) !== -1) {
config.headers.setContentType('application/x-www-form-urlencoded', false);
}
normalizeConfigURL(config);
const adapter = adapters.getAdapter(config.adapter || defaults.adapter, config);
return adapter(config).then(
function onAdapterResolution(response) {
throwIfCancellationRequested(config);
// Expose the current response on config so that transformResponse can
// attach it to any AxiosError it throws (e.g. on JSON parse failure).
// We clean it up afterwards to avoid polluting the config object.
config.response = response;
try {
response.data = transformData.call(config, config.transformResponse, response);
} finally {
delete config.response;
}
response.headers = AxiosHeaders.from(response.headers);
return response;
},
function onAdapterRejection(reason) {
if (!isCancel(reason)) {
throwIfCancellationRequested(config);
// Transform response data
if (reason && reason.response) {
config.response = reason.response;
try {
reason.response.data = transformData.call(
config,
config.transformResponse,
reason.response
);
} finally {
delete config.response;
}
reason.response.headers = AxiosHeaders.from(reason.response.headers);
}
}
return Promise.reject(reason);
}
);
}