fix(utils/ofetch): surface root causes in fetch errors (#22718)
* fix(ofetch): enhance error handling to surface root causes in fetch errors * fix(errors): remove duplicated error name on dev
This commit is contained in:
parent
2266ac7ec8
commit
097a56187f
|
|
@ -53,7 +53,7 @@ export const errorHandler: ErrorHandler = (error, ctx) => {
|
|||
});
|
||||
}
|
||||
|
||||
let errorMessage = (process.env.NODE_ENV || process.env.VERCEL_ENV) === 'production' ? error.message : error.stack || error.message;
|
||||
let errorMessage = (process.env.NODE_ENV || process.env.VERCEL_ENV) === 'production' || !error.stack ? `${error.name}: ${error.message}` : error.stack;
|
||||
switch (error.name) {
|
||||
case 'HTTPError':
|
||||
case 'RequestError':
|
||||
|
|
@ -75,9 +75,7 @@ export const errorHandler: ErrorHandler = (error, ctx) => {
|
|||
ctx.status(503);
|
||||
break;
|
||||
}
|
||||
const message = `${error.name}: ${errorMessage}`;
|
||||
|
||||
logger.error(`Error in ${requestPath}: ${message}`);
|
||||
logger.error(`Error in ${requestPath}: ${errorMessage}`);
|
||||
requestMetric.error({ path: matchedRoute, method: ctx.req.method, status: ctx.res.status });
|
||||
|
||||
return config.isPackage || ctx.req.query('format') === 'json'
|
||||
|
|
@ -86,7 +84,7 @@ export const errorHandler: ErrorHandler = (error, ctx) => {
|
|||
message: error.message ?? error,
|
||||
},
|
||||
})
|
||||
: ctx.html(<Error requestPath={requestPath} message={message} errorRoute={hasMatchedRoute ? matchedRoute : requestPath} nodeVersion={process.version} />);
|
||||
: ctx.html(<Error requestPath={requestPath} message={errorMessage} errorRoute={hasMatchedRoute ? matchedRoute : requestPath} nodeVersion={process.version} />);
|
||||
};
|
||||
|
||||
export const notFoundHandler: NotFoundHandler = (ctx) => errorHandler(new NotFoundError(), ctx);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,15 @@ describe('ofetch', () => {
|
|||
expect(warnSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('surfaces the root cause in fetch error messages', async () => {
|
||||
const { logger, ofetch } = await loadOfetchWithLogger();
|
||||
vi.spyOn(logger, 'error').mockImplementation(() => logger);
|
||||
const networkError = new TypeError('fetch failed', { cause: new Error('getaddrinfo ENOTFOUND t.me') });
|
||||
vi.stubGlobal('fetch', vi.fn().mockRejectedValue(networkError));
|
||||
|
||||
await expect(ofetch('https://t.me/s/telegram', { retry: 0 })).rejects.toThrow('fetch failed (getaddrinfo ENOTFOUND t.me)');
|
||||
});
|
||||
|
||||
it('logs redirected responses', async () => {
|
||||
const { logger, ofetch } = await loadOfetchWithLogger();
|
||||
const httpSpy = vi.spyOn(logger, 'http').mockImplementation(() => logger);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@ const rofetch = createFetch({ fetch: (input: Parameters<typeof fetch>[0], init?:
|
|||
},
|
||||
onRequestError({ request, error }) {
|
||||
logger.error(`Request ${request} fail: ${error.cause} ${error}`);
|
||||
for (let cause: unknown = error.cause; cause instanceof Error; cause = cause.cause) {
|
||||
if (cause.message) {
|
||||
error.message += ` (${cause.message})`;
|
||||
}
|
||||
}
|
||||
},
|
||||
onResponse({ request, response }) {
|
||||
if (response.redirected) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue