diff --git a/README.md b/README.md index 5923b53..22fde96 100644 --- a/README.md +++ b/README.md @@ -615,6 +615,9 @@ These are the available config options for making requests. Only the `url` is re // throw ETIMEDOUT error instead of generic ECONNABORTED on request timeouts clarifyTimeoutError: false, + + // use the legacy interceptor request/response ordering + legacyInterceptorReqResOrdering: true, // default }, env: { diff --git a/index.d.cts b/index.d.cts index 80d22db..7a4eff9 100644 --- a/index.d.cts +++ b/index.d.cts @@ -302,6 +302,7 @@ declare namespace axios { silentJSONParsing?: boolean; forcedJSONParsing?: boolean; clarifyTimeoutError?: boolean; + legacyInterceptorReqResOrdering?: boolean; } interface GenericAbortSignal { diff --git a/index.d.ts b/index.d.ts index 0ab1277..e9bdcd7 100644 --- a/index.d.ts +++ b/index.d.ts @@ -332,6 +332,7 @@ export interface TransitionalOptions { silentJSONParsing?: boolean; forcedJSONParsing?: boolean; clarifyTimeoutError?: boolean; + legacyInterceptorReqResOrdering?: boolean; } export interface GenericAbortSignal { diff --git a/lib/core/Axios.js b/lib/core/Axios.js index 0222e73..d3bbde0 100644 --- a/lib/core/Axios.js +++ b/lib/core/Axios.js @@ -8,6 +8,7 @@ import mergeConfig from './mergeConfig.js'; import buildFullPath from './buildFullPath.js'; import validator from '../helpers/validator.js'; import AxiosHeaders from './AxiosHeaders.js'; +import transitionalDefaults from '../defaults/transitional.js'; const validators = validator.validators; @@ -80,7 +81,8 @@ class Axios { validator.assertOptions(transitional, { silentJSONParsing: validators.transitional(validators.boolean), forcedJSONParsing: validators.transitional(validators.boolean), - clarifyTimeoutError: validators.transitional(validators.boolean) + clarifyTimeoutError: validators.transitional(validators.boolean), + legacyInterceptorReqResOrdering: validators.transitional(validators.boolean) }, false); } @@ -139,7 +141,14 @@ class Axios { synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous; - requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); + const transitional = config.transitional || transitionalDefaults; + const legacyInterceptorReqResOrdering = transitional && transitional.legacyInterceptorReqResOrdering; + + if (legacyInterceptorReqResOrdering) { + requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); + } else { + requestInterceptorChain.push(interceptor.fulfilled, interceptor.rejected); + } }); const responseInterceptorChain = []; diff --git a/lib/defaults/transitional.js b/lib/defaults/transitional.js index f891331..63d1c94 100644 --- a/lib/defaults/transitional.js +++ b/lib/defaults/transitional.js @@ -3,5 +3,6 @@ export default { silentJSONParsing: true, forcedJSONParsing: true, - clarifyTimeoutError: false + clarifyTimeoutError: false, + legacyInterceptorReqResOrdering: true }; diff --git a/test/specs/interceptors.spec.js b/test/specs/interceptors.spec.js index d08bcba..3ff4f36 100644 --- a/test/specs/interceptors.spec.js +++ b/test/specs/interceptors.spec.js @@ -91,6 +91,63 @@ describe('interceptors', function () { }); }); + it('should execute request interceptor in legacy order', function (done) { + let sequence = ''; + axios.interceptors.request.use(function (config) { + sequence += '1'; + return config; + }); + + axios.interceptors.request.use(function (config) { + sequence += '2'; + return config; + }); + + axios.interceptors.request.use(function (config) { + sequence += '3'; + return config; + }); + + axios({ + url: '/foo', + }); + + getAjaxRequest().then(function (request) { + expect(sequence).toBe('321'); + done(); + }); + }); + + it('should execute request interceptor in order', function (done) { + let sequence = ''; + axios.interceptors.request.use(function (config) { + sequence += '1'; + return config; + }); + + axios.interceptors.request.use(function (config) { + sequence += '2'; + return config; + }); + + axios.interceptors.request.use(function (config) { + sequence += '3'; + return config; + }); + + axios({ + url: '/foo', + transitional: { + legacyInterceptorReqResOrdering: false + } + }); + + getAjaxRequest().then(function (request) { + expect(sequence).toBe('123'); + done(); + }); + }); + it('runs the interceptor if runWhen function is provided and resolves to true', function (done) { function onGetCall(config) { return config.method === 'get'; @@ -343,7 +400,7 @@ describe('interceptors', function () { function fireRequestAndExpect(expectation) { let response; - axios('/foo').then(function(data) { + axios('/foo').then(function (data) { response = data; }); getAjaxRequest().then(function (request) { @@ -352,7 +409,7 @@ describe('interceptors', function () { responseText: 'OK' }); - setTimeout(function() { + setTimeout(function () { expectation(response) }, 100); }); @@ -384,10 +441,10 @@ describe('interceptors', function () { }); it('then only the last interceptor\'s result is returned', function (done) { - axios.interceptors.response.use(function() { + axios.interceptors.response.use(function () { return 'response 1'; }); - axios.interceptors.response.use(function() { + axios.interceptors.response.use(function () { return 'response 2'; }); @@ -398,10 +455,10 @@ describe('interceptors', function () { }); it('then every interceptor receives the result of it\'s predecessor', function (done) { - axios.interceptors.response.use(function() { + axios.interceptors.response.use(function () { return 'response 1'; }); - axios.interceptors.response.use(function(response) { + axios.interceptors.response.use(function (response) { return [response, 'response 2']; }); @@ -414,7 +471,7 @@ describe('interceptors', function () { describe('and when the fulfillment-interceptor throws', function () { function fireRequestCatchAndExpect(expectation) { - axios('/foo').catch(function(data) { + axios('/foo').catch(function (data) { // dont handle result }); getAjaxRequest().then(function (request) { @@ -423,14 +480,14 @@ describe('interceptors', function () { responseText: 'OK' }); - setTimeout(function() { + setTimeout(function () { expectation() }, 100); }); } it('then the following fulfillment-interceptor is not called', function (done) { - axios.interceptors.response.use(function() { + axios.interceptors.response.use(function () { throw Error('throwing interceptor'); }); const interceptor2 = jasmine.createSpy('interceptor2'); @@ -443,10 +500,10 @@ describe('interceptors', function () { }); it('then the following rejection-interceptor is called', function (done) { - axios.interceptors.response.use(function() { + axios.interceptors.response.use(function () { throw Error('throwing interceptor'); }); - const unusedFulfillInterceptor = function() {}; + const unusedFulfillInterceptor = function () { }; const rejectIntercept = jasmine.createSpy('rejectIntercept'); axios.interceptors.response.use(unusedFulfillInterceptor, rejectIntercept); @@ -457,12 +514,12 @@ describe('interceptors', function () { }); it('once caught, another following fulfill-interceptor is called again (just like in a promise chain)', function (done) { - axios.interceptors.response.use(function() { + axios.interceptors.response.use(function () { throw Error('throwing interceptor'); }); - const unusedFulfillInterceptor = function() {}; - const catchingThrowingInterceptor = function() {}; + const unusedFulfillInterceptor = function () { }; + const catchingThrowingInterceptor = function () { }; axios.interceptors.response.use(unusedFulfillInterceptor, catchingThrowingInterceptor); const interceptor3 = jasmine.createSpy('interceptor3');