mirror of
https://github.com/tenrok/axios.git
synced 2026-06-20 20:00:40 +03:00
fix: wrap errors to improve async stack trace (#5987)
This commit is contained in:
+22
-1
@@ -35,7 +35,28 @@ class Axios {
|
|||||||
*
|
*
|
||||||
* @returns {Promise} The Promise to be fulfilled
|
* @returns {Promise} The Promise to be fulfilled
|
||||||
*/
|
*/
|
||||||
request(configOrUrl, config) {
|
async request(configOrUrl, config) {
|
||||||
|
try {
|
||||||
|
return await this._request(configOrUrl, config);
|
||||||
|
} catch (err) {
|
||||||
|
const dummy = {}
|
||||||
|
if (Error.captureStackTrace) {
|
||||||
|
Error.captureStackTrace(dummy)
|
||||||
|
} else {
|
||||||
|
dummy.stack = new Error().stack;
|
||||||
|
}
|
||||||
|
// slice off the Error: ... line
|
||||||
|
dummy.stack = dummy.stack.replace(/^.+\n/, '');
|
||||||
|
// match without the 2 top stack lines
|
||||||
|
if (!err.stack.endsWith(dummy.stack.replace(/^.+\n.+\n/, ''))) {
|
||||||
|
err.stack += '\n' + dummy.stack
|
||||||
|
}
|
||||||
|
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_request(configOrUrl, config) {
|
||||||
/*eslint no-param-reassign:0*/
|
/*eslint no-param-reassign:0*/
|
||||||
// Allow for axios('example/url'[, config]) a la fetch API
|
// Allow for axios('example/url'[, config]) a la fetch API
|
||||||
if (typeof configOrUrl === 'string') {
|
if (typeof configOrUrl === 'string') {
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ function toleranceRange(positive, negative) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nodeVersion = process.versions.node.split('.').map(v => parseInt(v, 10));
|
||||||
|
const nodeMajorVersion = nodeVersion[0];
|
||||||
|
|
||||||
var noop = ()=> {};
|
var noop = ()=> {};
|
||||||
|
|
||||||
const LOCAL_SERVER_URL = 'http://localhost:4444';
|
const LOCAL_SERVER_URL = 'http://localhost:4444';
|
||||||
@@ -446,6 +449,57 @@ describe('supports http with nodejs', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should wrap HTTP errors and keep stack', function (done) {
|
||||||
|
if (nodeMajorVersion <= 12) {
|
||||||
|
this.skip(); // node 12 support for async stack traces appears lacking
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
server = http.createServer(function (req, res) {
|
||||||
|
res.statusCode = 400;
|
||||||
|
res.end();
|
||||||
|
}).listen(4444, function () {
|
||||||
|
void assert.rejects(
|
||||||
|
async function findMeInStackTrace() {
|
||||||
|
await axios.head('http://localhost:4444/one')
|
||||||
|
},
|
||||||
|
function (err) {
|
||||||
|
assert.equal(err.name, 'AxiosError')
|
||||||
|
assert.equal(err.isAxiosError, true)
|
||||||
|
const matches = [...err.stack.matchAll(/findMeInStackTrace/g)]
|
||||||
|
assert.equal(matches.length, 1, err.stack)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
).then(done).catch(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should wrap interceptor errors and keep stack', function (done) {
|
||||||
|
if (nodeMajorVersion <= 12) {
|
||||||
|
this.skip(); // node 12 support for async stack traces appears lacking
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const axiosInstance = axios.create();
|
||||||
|
axiosInstance.interceptors.request.use((res) => {
|
||||||
|
throw new Error('from request interceptor')
|
||||||
|
});
|
||||||
|
server = http.createServer(function (req, res) {
|
||||||
|
res.end();
|
||||||
|
}).listen(4444, function () {
|
||||||
|
void assert.rejects(
|
||||||
|
async function findMeInStackTrace() {
|
||||||
|
await axiosInstance.get('http://localhost:4444/one')
|
||||||
|
},
|
||||||
|
function (err) {
|
||||||
|
assert.equal(err.name, 'Error')
|
||||||
|
assert.equal(err.message, 'from request interceptor')
|
||||||
|
const matches = [...err.stack.matchAll(/findMeInStackTrace/g)]
|
||||||
|
assert.equal(matches.length, 1, err.stack)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
).then(done).catch(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should preserve the HTTP verb on redirect', function (done) {
|
it('should preserve the HTTP verb on redirect', function (done) {
|
||||||
server = http.createServer(function (req, res) {
|
server = http.createServer(function (req, res) {
|
||||||
if (req.method.toLowerCase() !== "head") {
|
if (req.method.toLowerCase() !== "head") {
|
||||||
@@ -1384,13 +1438,21 @@ describe('supports http with nodejs', function () {
|
|||||||
// call cancel() when the request has been sent, but a response has not been received
|
// call cancel() when the request has been sent, but a response has not been received
|
||||||
source.cancel('Operation has been canceled.');
|
source.cancel('Operation has been canceled.');
|
||||||
}).listen(4444, function () {
|
}).listen(4444, function () {
|
||||||
axios.get('http://localhost:4444/', {
|
void assert.rejects(
|
||||||
cancelToken: source.token
|
async function findMeInStackTrace() {
|
||||||
}).catch(function (thrown) {
|
await axios.get('http://localhost:4444/', {
|
||||||
assert.ok(thrown instanceof axios.Cancel, 'Promise must be rejected with a CanceledError object');
|
cancelToken: source.token
|
||||||
assert.equal(thrown.message, 'Operation has been canceled.');
|
});
|
||||||
done();
|
},
|
||||||
});
|
function (thrown) {
|
||||||
|
assert.ok(thrown instanceof axios.Cancel, 'Promise must be rejected with a CanceledError object');
|
||||||
|
assert.equal(thrown.message, 'Operation has been canceled.');
|
||||||
|
if (nodeMajorVersion > 12) {
|
||||||
|
assert.match(thrown.stack, /findMeInStackTrace/);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
).then(done).catch(done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user