2
0
mirror of https://github.com/tenrok/axios.git synced 2026-05-15 11:59:42 +03:00

fix: added a option to choose between legacy and the new request/response interceptor ordering

* test: add request interceptor tests for legacy and ordered execution

* feat: add legacy interceptor request/response ordering option

---------

Co-authored-by: Jay <jasonsaayman@gmail.com>
This commit is contained in:
Willian Agostini
2026-01-30 03:12:04 -03:00
committed by GitHub
parent 44b7c9f0c4
commit 569f028a58
6 changed files with 89 additions and 17 deletions
+3
View File
@@ -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 // throw ETIMEDOUT error instead of generic ECONNABORTED on request timeouts
clarifyTimeoutError: false, clarifyTimeoutError: false,
// use the legacy interceptor request/response ordering
legacyInterceptorReqResOrdering: true, // default
}, },
env: { env: {
+1
View File
@@ -302,6 +302,7 @@ declare namespace axios {
silentJSONParsing?: boolean; silentJSONParsing?: boolean;
forcedJSONParsing?: boolean; forcedJSONParsing?: boolean;
clarifyTimeoutError?: boolean; clarifyTimeoutError?: boolean;
legacyInterceptorReqResOrdering?: boolean;
} }
interface GenericAbortSignal { interface GenericAbortSignal {
Vendored
+1
View File
@@ -332,6 +332,7 @@ export interface TransitionalOptions {
silentJSONParsing?: boolean; silentJSONParsing?: boolean;
forcedJSONParsing?: boolean; forcedJSONParsing?: boolean;
clarifyTimeoutError?: boolean; clarifyTimeoutError?: boolean;
legacyInterceptorReqResOrdering?: boolean;
} }
export interface GenericAbortSignal { export interface GenericAbortSignal {
+11 -2
View File
@@ -8,6 +8,7 @@ import mergeConfig from './mergeConfig.js';
import buildFullPath from './buildFullPath.js'; import buildFullPath from './buildFullPath.js';
import validator from '../helpers/validator.js'; import validator from '../helpers/validator.js';
import AxiosHeaders from './AxiosHeaders.js'; import AxiosHeaders from './AxiosHeaders.js';
import transitionalDefaults from '../defaults/transitional.js';
const validators = validator.validators; const validators = validator.validators;
@@ -80,7 +81,8 @@ class Axios {
validator.assertOptions(transitional, { validator.assertOptions(transitional, {
silentJSONParsing: validators.transitional(validators.boolean), silentJSONParsing: validators.transitional(validators.boolean),
forcedJSONParsing: 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); }, false);
} }
@@ -139,7 +141,14 @@ class Axios {
synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous; 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 = []; const responseInterceptorChain = [];
+2 -1
View File
@@ -3,5 +3,6 @@
export default { export default {
silentJSONParsing: true, silentJSONParsing: true,
forcedJSONParsing: true, forcedJSONParsing: true,
clarifyTimeoutError: false clarifyTimeoutError: false,
legacyInterceptorReqResOrdering: true
}; };
+71 -14
View File
@@ -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) { it('runs the interceptor if runWhen function is provided and resolves to true', function (done) {
function onGetCall(config) { function onGetCall(config) {
return config.method === 'get'; return config.method === 'get';
@@ -343,7 +400,7 @@ describe('interceptors', function () {
function fireRequestAndExpect(expectation) { function fireRequestAndExpect(expectation) {
let response; let response;
axios('/foo').then(function(data) { axios('/foo').then(function (data) {
response = data; response = data;
}); });
getAjaxRequest().then(function (request) { getAjaxRequest().then(function (request) {
@@ -352,7 +409,7 @@ describe('interceptors', function () {
responseText: 'OK' responseText: 'OK'
}); });
setTimeout(function() { setTimeout(function () {
expectation(response) expectation(response)
}, 100); }, 100);
}); });
@@ -384,10 +441,10 @@ describe('interceptors', function () {
}); });
it('then only the last interceptor\'s result is returned', function (done) { 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'; return 'response 1';
}); });
axios.interceptors.response.use(function() { axios.interceptors.response.use(function () {
return 'response 2'; return 'response 2';
}); });
@@ -398,10 +455,10 @@ describe('interceptors', function () {
}); });
it('then every interceptor receives the result of it\'s predecessor', function (done) { 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'; return 'response 1';
}); });
axios.interceptors.response.use(function(response) { axios.interceptors.response.use(function (response) {
return [response, 'response 2']; return [response, 'response 2'];
}); });
@@ -414,7 +471,7 @@ describe('interceptors', function () {
describe('and when the fulfillment-interceptor throws', function () { describe('and when the fulfillment-interceptor throws', function () {
function fireRequestCatchAndExpect(expectation) { function fireRequestCatchAndExpect(expectation) {
axios('/foo').catch(function(data) { axios('/foo').catch(function (data) {
// dont handle result // dont handle result
}); });
getAjaxRequest().then(function (request) { getAjaxRequest().then(function (request) {
@@ -423,14 +480,14 @@ describe('interceptors', function () {
responseText: 'OK' responseText: 'OK'
}); });
setTimeout(function() { setTimeout(function () {
expectation() expectation()
}, 100); }, 100);
}); });
} }
it('then the following fulfillment-interceptor is not called', function (done) { 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'); throw Error('throwing interceptor');
}); });
const interceptor2 = jasmine.createSpy('interceptor2'); const interceptor2 = jasmine.createSpy('interceptor2');
@@ -443,10 +500,10 @@ describe('interceptors', function () {
}); });
it('then the following rejection-interceptor is called', function (done) { it('then the following rejection-interceptor is called', function (done) {
axios.interceptors.response.use(function() { axios.interceptors.response.use(function () {
throw Error('throwing interceptor'); throw Error('throwing interceptor');
}); });
const unusedFulfillInterceptor = function() {}; const unusedFulfillInterceptor = function () { };
const rejectIntercept = jasmine.createSpy('rejectIntercept'); const rejectIntercept = jasmine.createSpy('rejectIntercept');
axios.interceptors.response.use(unusedFulfillInterceptor, 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) { 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'); throw Error('throwing interceptor');
}); });
const unusedFulfillInterceptor = function() {}; const unusedFulfillInterceptor = function () { };
const catchingThrowingInterceptor = function() {}; const catchingThrowingInterceptor = function () { };
axios.interceptors.response.use(unusedFulfillInterceptor, catchingThrowingInterceptor); axios.interceptors.response.use(unusedFulfillInterceptor, catchingThrowingInterceptor);
const interceptor3 = jasmine.createSpy('interceptor3'); const interceptor3 = jasmine.createSpy('interceptor3');