mirror of
https://github.com/tenrok/axios.git
synced 2026-06-17 19:21:29 +03:00
fix(http): preserve response in error when stream is aborted after headers (#10708)
* fix(http): preserve response in error when stream is aborted after headers When a server sends response headers but aborts the stream before completing the body, axios now attaches the response object to the error. This allows consumers to access response metadata (status, headers) for debugging, retry logic, or user messaging. Fixes #6935 * fix(http): normalize response stream errors --------- Co-authored-by: Jay <jasonsaayman@gmail.com>
This commit is contained in:
@@ -904,7 +904,8 @@ export default isHttpAdapterSupported &&
|
|||||||
'stream has been aborted',
|
'stream has been aborted',
|
||||||
AxiosError.ERR_BAD_RESPONSE,
|
AxiosError.ERR_BAD_RESPONSE,
|
||||||
config,
|
config,
|
||||||
lastRequest
|
lastRequest,
|
||||||
|
response
|
||||||
);
|
);
|
||||||
responseStream.destroy(err);
|
responseStream.destroy(err);
|
||||||
reject(err);
|
reject(err);
|
||||||
@@ -912,7 +913,7 @@ export default isHttpAdapterSupported &&
|
|||||||
|
|
||||||
responseStream.on('error', function handleStreamError(err) {
|
responseStream.on('error', function handleStreamError(err) {
|
||||||
if (req.destroyed) return;
|
if (req.destroyed) return;
|
||||||
reject(AxiosError.from(err, null, config, lastRequest));
|
reject(AxiosError.from(err, null, config, lastRequest, response));
|
||||||
});
|
});
|
||||||
|
|
||||||
responseStream.on('end', function handleStreamEnd() {
|
responseStream.on('end', function handleStreamEnd() {
|
||||||
|
|||||||
@@ -612,17 +612,28 @@ describe('supports http with nodejs', () => {
|
|||||||
it('should support gunzip error handling', async () => {
|
it('should support gunzip error handling', async () => {
|
||||||
const server = await startHTTPServer(
|
const server = await startHTTPServer(
|
||||||
(req, res) => {
|
(req, res) => {
|
||||||
|
res.statusCode = 206;
|
||||||
res.setHeader('Content-Type', 'application/json');
|
res.setHeader('Content-Type', 'application/json');
|
||||||
res.setHeader('Content-Encoding', 'gzip');
|
res.setHeader('Content-Encoding', 'gzip');
|
||||||
|
res.setHeader('X-Stream-Error', 'yes');
|
||||||
res.end('invalid response');
|
res.end('invalid response');
|
||||||
},
|
},
|
||||||
{ port: SERVER_PORT }
|
{ port: SERVER_PORT }
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await assert.rejects(async () => {
|
await assert.rejects(
|
||||||
await axios.get(`http://localhost:${server.address().port}/`);
|
async () => {
|
||||||
});
|
await axios.get(`http://localhost:${server.address().port}/`);
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
assert.strictEqual(error.response.status, 206);
|
||||||
|
assert.strictEqual(error.response.headers.get('x-stream-error'), 'yes');
|
||||||
|
assert.strictEqual(error.status, 206);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
await stopHTTPServer(server);
|
await stopHTTPServer(server);
|
||||||
}
|
}
|
||||||
@@ -2692,7 +2703,7 @@ describe('supports http with nodejs', () => {
|
|||||||
it('should throw an error if http server that aborts a chunked request', async () => {
|
it('should throw an error if http server that aborts a chunked request', async () => {
|
||||||
const server = await startHTTPServer(
|
const server = await startHTTPServer(
|
||||||
(req, res) => {
|
(req, res) => {
|
||||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
res.writeHead(200, { 'Content-Type': 'text/plain', 'X-Stream-Aborted': 'yes' });
|
||||||
res.write('chunk 1');
|
res.write('chunk 1');
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -2714,6 +2725,9 @@ describe('supports http with nodejs', () => {
|
|||||||
(error) => {
|
(error) => {
|
||||||
assert.strictEqual(error.code, 'ERR_BAD_RESPONSE');
|
assert.strictEqual(error.code, 'ERR_BAD_RESPONSE');
|
||||||
assert.strictEqual(error.message, 'stream has been aborted');
|
assert.strictEqual(error.message, 'stream has been aborted');
|
||||||
|
assert.strictEqual(error.response.status, 200);
|
||||||
|
assert.strictEqual(error.response.headers.get('x-stream-aborted'), 'yes');
|
||||||
|
assert.strictEqual(error.status, 200);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user