From 34adfd90efc9c145488399e1cf7fa96de67080fa Mon Sep 17 00:00:00 2001 From: Jay Date: Sun, 10 May 2026 08:56:26 +0200 Subject: [PATCH] revert: "fix: support URL object as config.url input (#10866)" (#10874) This reverts commit 847d89b43654405d9a231e0b669832c2092b621f. --- README.md | 9 --- index.d.cts | 26 ++++---- index.d.ts | 26 ++++---- lib/core/Axios.js | 28 +-------- lib/core/dispatchRequest.js | 23 ------- lib/helpers/buildURL.js | 6 -- tests/unit/adapters/http.test.js | 40 ------------ tests/unit/api.test.js | 98 ----------------------------- tests/unit/helpers/buildURL.test.js | 45 ------------- 9 files changed, 29 insertions(+), 272 deletions(-) diff --git a/README.md b/README.md index dc0246a6..a32220a0 100644 --- a/README.md +++ b/README.md @@ -592,20 +592,11 @@ response.data.pipe(fs.createWriteStream('ada_lovelace.jpg')); ##### axios(url[, config]) -`url` accepts either a string or a [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) instance. The `URL` is coerced to a string before the request is dispatched. - ```js // Send a GET request (default method) axios('/user/12345'); ``` -```js -// `url` may also be a URL object -axios.get(new URL('https://api.example.com/foo'), { - params: { a: 1 }, -}); -``` - ### Request method aliases For convenience, aliases have been provided for all common request methods. diff --git a/index.d.cts b/index.d.cts index b4480f44..916b9958 100644 --- a/index.d.cts +++ b/index.d.cts @@ -176,53 +176,53 @@ declare class Axios { config: axios.AxiosRequestConfig ): Promise; get, D = any>( - url: string | URL, + url: string, config?: axios.AxiosRequestConfig ): Promise; delete, D = any>( - url: string | URL, + url: string, config?: axios.AxiosRequestConfig ): Promise; head, D = any>( - url: string | URL, + url: string, config?: axios.AxiosRequestConfig ): Promise; options, D = any>( - url: string | URL, + url: string, config?: axios.AxiosRequestConfig ): Promise; post, D = any>( - url: string | URL, + url: string, data?: D, config?: axios.AxiosRequestConfig ): Promise; put, D = any>( - url: string | URL, + url: string, data?: D, config?: axios.AxiosRequestConfig ): Promise; patch, D = any>( - url: string | URL, + url: string, data?: D, config?: axios.AxiosRequestConfig ): Promise; postForm, D = any>( - url: string | URL, + url: string, data?: D, config?: axios.AxiosRequestConfig ): Promise; putForm, D = any>( - url: string | URL, + url: string, data?: D, config?: axios.AxiosRequestConfig ): Promise; patchForm, D = any>( - url: string | URL, + url: string, data?: D, config?: axios.AxiosRequestConfig ): Promise; query, D = any>( - url: string | URL, + url: string, data?: D, config?: axios.AxiosRequestConfig ): Promise; @@ -473,7 +473,7 @@ declare namespace axios { type LookupAddress = string | LookupAddressEntry; interface AxiosRequestConfig { - url?: string | URL; + url?: string; method?: Method | string; baseURL?: string; allowAbsoluteUrls?: boolean; @@ -661,7 +661,7 @@ declare namespace axios { interface AxiosInstance extends Axios { , D = any>(config: AxiosRequestConfig): Promise; , D = any>( - url: string | URL, + url: string, config?: AxiosRequestConfig ): Promise; diff --git a/index.d.ts b/index.d.ts index 6ae23e79..e25555fa 100644 --- a/index.d.ts +++ b/index.d.ts @@ -364,7 +364,7 @@ export interface LookupAddressEntry { export type LookupAddress = string | LookupAddressEntry; export interface AxiosRequestConfig { - url?: string | URL; + url?: string; method?: StringLiteralsOrString; baseURL?: string; allowAbsoluteUrls?: boolean; @@ -609,53 +609,53 @@ export class Axios { getUri(config?: AxiosRequestConfig): string; request, D = any>(config: AxiosRequestConfig): Promise; get, D = any>( - url: string | URL, + url: string, config?: AxiosRequestConfig ): Promise; delete, D = any>( - url: string | URL, + url: string, config?: AxiosRequestConfig ): Promise; head, D = any>( - url: string | URL, + url: string, config?: AxiosRequestConfig ): Promise; options, D = any>( - url: string | URL, + url: string, config?: AxiosRequestConfig ): Promise; post, D = any>( - url: string | URL, + url: string, data?: D, config?: AxiosRequestConfig ): Promise; put, D = any>( - url: string | URL, + url: string, data?: D, config?: AxiosRequestConfig ): Promise; patch, D = any>( - url: string | URL, + url: string, data?: D, config?: AxiosRequestConfig ): Promise; postForm, D = any>( - url: string | URL, + url: string, data?: D, config?: AxiosRequestConfig ): Promise; putForm, D = any>( - url: string | URL, + url: string, data?: D, config?: AxiosRequestConfig ): Promise; patchForm, D = any>( - url: string | URL, + url: string, data?: D, config?: AxiosRequestConfig ): Promise; query, D = any>( - url: string | URL, + url: string, data?: D, config?: AxiosRequestConfig ): Promise; @@ -663,7 +663,7 @@ export class Axios { export interface AxiosInstance extends Axios { , D = any>(config: AxiosRequestConfig): Promise; - , D = any>(url: string | URL, config?: AxiosRequestConfig): Promise; + , D = any>(url: string, config?: AxiosRequestConfig): Promise; create(config?: CreateAxiosDefaults): AxiosInstance; defaults: Omit & { diff --git a/lib/core/Axios.js b/lib/core/Axios.js index 39d8d913..903249a8 100644 --- a/lib/core/Axios.js +++ b/lib/core/Axios.js @@ -12,19 +12,6 @@ import transitionalDefaults from '../defaults/transitional.js'; const validators = validator.validators; -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); - /** * Create a new instance of Axios * @@ -44,7 +31,7 @@ class Axios { /** * Dispatch a request * - * @param {String|URL|Object} configOrUrl The config specific for this request (merged with this.defaults) + * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults) * @param {?Object} config * * @returns {Promise} The Promise to be fulfilled @@ -95,19 +82,13 @@ class Axios { _request(configOrUrl, config) { /*eslint no-param-reassign:0*/ // Allow for axios('example/url'[, config]) a la fetch API - if (typeof configOrUrl === 'string' || isURL(configOrUrl)) { + if (typeof configOrUrl === 'string') { config = config || {}; - config.url = normalizeURL(configOrUrl); + config.url = configOrUrl; } else { config = configOrUrl || {}; } - // Coerce config.url to a string if it's a URL object, so that all downstream - // consumers (buildFullPath, combineURLs, adapters) see a string. - if (isURL(config.url)) { - config.url = normalizeURL(config.url); - } - config = mergeConfig(this.defaults, config); const { transitional, paramsSerializer, headers } = config; @@ -251,9 +232,6 @@ class Axios { getUri(config) { config = mergeConfig(this.defaults, config); - if (isURL(config.url)) { - config.url = normalizeURL(config.url); - } const fullPath = buildFullPath(config.baseURL, config.url, config.allowAbsoluteUrls); return buildURL(fullPath, config.params, config.paramsSerializer); } diff --git a/lib/core/dispatchRequest.js b/lib/core/dispatchRequest.js index fd1c3e5f..59662d46 100644 --- a/lib/core/dispatchRequest.js +++ b/lib/core/dispatchRequest.js @@ -7,25 +7,6 @@ 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. * @@ -51,8 +32,6 @@ function throwIfCancellationRequested(config) { * @returns {Promise} The Promise to be fulfilled */ export default function dispatchRequest(config) { - normalizeConfigURL(config); - throwIfCancellationRequested(config); config.headers = AxiosHeaders.from(config.headers); @@ -64,8 +43,6 @@ export default function dispatchRequest(config) { config.headers.setContentType('application/x-www-form-urlencoded', false); } - normalizeConfigURL(config); - const adapter = adapters.getAdapter(config.adapter || defaults.adapter, config); return adapter(config).then( diff --git a/lib/helpers/buildURL.js b/lib/helpers/buildURL.js index 2698a8f0..b3e230e5 100644 --- a/lib/helpers/buildURL.js +++ b/lib/helpers/buildURL.js @@ -29,12 +29,6 @@ export function encode(val) { * @returns {string} The formatted url */ export default function buildURL(url, params, options) { - // Safeguard for direct callers (e.g. via ./unsafe/helpers/buildURL.js): coerce URL-like - // objects to strings before using string methods below. - if (url !== null && typeof url === 'object' && typeof url.toString === 'function') { - url = url.toString(); - } - if (!params) { return url; } diff --git a/tests/unit/adapters/http.test.js b/tests/unit/adapters/http.test.js index f610a97f..56e2e934 100644 --- a/tests/unit/adapters/http.test.js +++ b/tests/unit/adapters/http.test.js @@ -3116,46 +3116,6 @@ describe('supports http with nodejs', () => { } }); - it('should support URL object with params', async () => { - const server = await startHTTPServer( - (req, res) => { - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({ url: req.url })); - }, - { port: SERVER_PORT } - ); - - try { - const url = new URL(`http://localhost:${server.address().port}/foo?a=1`); - const response = await axios.get(url, { params: { b: '2' } }); - - assert.strictEqual(response.status, 200); - assert.strictEqual(response.data.url, '/foo?a=1&b=2'); - } finally { - await stopHTTPServer(server); - } - }); - - it('should support URL object without params (no crash)', async () => { - const server = await startHTTPServer( - (req, res) => { - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({ url: req.url })); - }, - { port: SERVER_PORT } - ); - - try { - const url = new URL(`http://localhost:${server.address().port}/foo`); - const response = await axios.get(url); - - assert.strictEqual(response.status, 200); - assert.strictEqual(response.data.url, '/foo'); - } finally { - await stopHTTPServer(server); - } - }); - it('should support HTTP protocol', async () => { const server = await startHTTPServer( (req, res) => { diff --git a/tests/unit/api.test.js b/tests/unit/api.test.js index a8070ad0..bcfd2ec4 100644 --- a/tests/unit/api.test.js +++ b/tests/unit/api.test.js @@ -35,94 +35,6 @@ describe('static api', () => { await promise; }); - it('should support URL object shorthand with config', async () => { - const url = new URL('http://example.com/test?a=1'); - - const response = await axios(url, { - params: { - b: 2, - }, - adapter: (config) => - Promise.resolve({ - data: null, - status: 200, - statusText: 'OK', - headers: {}, - config, - request: {}, - }), - }); - - assert.strictEqual(response.config.url, url.toString()); - assert.deepStrictEqual(response.config.params, { b: 2 }); - }); - - it('should not require global URL to be a constructor for string requests', async () => { - const descriptor = Object.getOwnPropertyDescriptor(globalThis, 'URL'); - - Object.defineProperty(globalThis, 'URL', { - configurable: true, - writable: true, - value: {}, - }); - - try { - const response = await axios('/test', { - adapter: (config) => - Promise.resolve({ - data: null, - status: 200, - statusText: 'OK', - headers: {}, - config, - request: {}, - }), - }); - - assert.strictEqual(response.config.url, '/test'); - } finally { - if (descriptor) { - Object.defineProperty(globalThis, 'URL', descriptor); - } else { - delete globalThis.URL; - } - } - }); - - it('should normalize URL object set by a request interceptor before dispatch', async () => { - const url = new URL('http://example.com/interceptor'); - let transformUrl; - const interceptorId = axios.interceptors.request.use((config) => { - config.url = url; - return config; - }); - - try { - const response = await axios('/test', { - transformRequest: [ - function (data) { - transformUrl = this.url; - return data; - }, - ], - adapter: (config) => - Promise.resolve({ - data: null, - status: 200, - statusText: 'OK', - headers: {}, - config, - request: {}, - }), - }); - - assert.strictEqual(transformUrl, url.toString()); - assert.strictEqual(response.config.url, url.toString()); - } finally { - axios.interceptors.request.eject(interceptorId); - } - }); - it('should have defaults', () => { assert.strictEqual(typeof axios.defaults, 'object'); assert.strictEqual(typeof axios.defaults.headers, 'object'); @@ -157,16 +69,6 @@ describe('static api', () => { assert.strictEqual(typeof axios.getUri, 'function'); }); - it('should support URL object config in getUri', () => { - const url = new URL('https://api.example.com/foo'); - - assert.strictEqual(axios.getUri({ url }), url.toString()); - assert.strictEqual( - axios.getUri({ baseURL: 'https://example.com/base', url }), - url.toString() - ); - }); - it('should have isAxiosError properties', () => { assert.strictEqual(typeof axios.isAxiosError, 'function'); }); diff --git a/tests/unit/helpers/buildURL.test.js b/tests/unit/helpers/buildURL.test.js index ee62a245..6f114c06 100644 --- a/tests/unit/helpers/buildURL.test.js +++ b/tests/unit/helpers/buildURL.test.js @@ -101,51 +101,6 @@ describe('helpers::buildURL', () => { expect(buildURL('/foo', new URLSearchParams('bar=baz'))).toEqual('/foo?bar=baz'); }); - it('should support URL object without params', () => { - const url = new URL('http://example.com/foo?a=1'); - expect(buildURL(url)).toEqual('http://example.com/foo?a=1'); - }); - - it('should support URL object with params', () => { - const url = new URL('http://example.com/foo?a=1'); - expect(buildURL(url, { b: 2 })).toEqual('http://example.com/foo?a=1&b=2'); - }); - - it('should support URL-like object with params', () => { - const url = { - toString() { - return 'http://example.com/foo?a=1'; - }, - }; - - expect(buildURL(url, { b: 2 })).toEqual('http://example.com/foo?a=1&b=2'); - }); - - it('should not require global URL to be a constructor', () => { - const descriptor = Object.getOwnPropertyDescriptor(globalThis, 'URL'); - const url = { - toString() { - return 'http://example.com/foo?a=1'; - }, - }; - - Object.defineProperty(globalThis, 'URL', { - configurable: true, - writable: true, - value: {}, - }); - - try { - expect(buildURL(url, { b: 2 })).toEqual('http://example.com/foo?a=1&b=2'); - } finally { - if (descriptor) { - Object.defineProperty(globalThis, 'URL', descriptor); - } else { - delete globalThis.URL; - } - } - }); - it('should support custom serialize function', () => { const params = { x: 1,