rsshub / lib /errors /index.tsx
asemxin
Initial commit for HF Spaces
bf48b89
import * as Sentry from '@sentry/node';
import type { ErrorHandler, NotFoundHandler } from 'hono';
import { routePath } from 'hono/route';
import { config } from '@/config';
import { getDebugInfo, setDebugInfo } from '@/utils/debug-info';
import logger from '@/utils/logger';
import { requestMetric } from '@/utils/otel';
import Error from '@/views/error';
import NotFoundError from './types/not-found';
export const errorHandler: ErrorHandler = (error, ctx) => {
const requestPath = ctx.req.path;
const matchedRoute = routePath(ctx);
const hasMatchedRoute = matchedRoute !== '/*';
const debug = getDebugInfo();
try {
if (ctx.res.headers.get('RSSHub-Cache-Status')) {
debug.hitCache++;
}
} catch {
// ignore
}
debug.error++;
if (!debug.errorPaths[requestPath]) {
debug.errorPaths[requestPath] = 0;
}
debug.errorPaths[requestPath]++;
if (!debug.errorRoutes[matchedRoute] && hasMatchedRoute) {
debug.errorRoutes[matchedRoute] = 0;
}
hasMatchedRoute && debug.errorRoutes[matchedRoute]++;
setDebugInfo(debug);
if (config.sentry.dsn) {
Sentry.withScope((scope) => {
scope.setTag('name', requestPath.split('/')[1]);
Sentry.captureException(error);
});
}
let errorMessage = (process.env.NODE_ENV || process.env.VERCEL_ENV) === 'production' ? error.message : error.stack || error.message;
switch (error.constructor.name) {
case 'HTTPError':
case 'RequestError':
case 'FetchError':
ctx.status(503);
break;
case 'RequestInProgressError':
ctx.header('Cache-Control', `public, max-age=${config.requestTimeout / 1000}`);
ctx.status(503);
break;
case 'RejectError':
ctx.status(403);
break;
case 'NotFoundError':
ctx.status(404);
errorMessage += 'The route does not exist or has been deleted.';
break;
default:
ctx.status(503);
break;
}
const message = `${error.name}: ${errorMessage}`;
logger.error(`Error in ${requestPath}: ${message}`);
requestMetric.error({ path: matchedRoute, method: ctx.req.method, status: ctx.res.status });
return config.isPackage || ctx.req.query('format') === 'json'
? ctx.json({
error: {
message: error.message ?? error,
},
})
: ctx.html(<Error requestPath={requestPath} message={message} errorRoute={hasMatchedRoute ? matchedRoute : requestPath} nodeVersion={process.version} />);
};
export const notFoundHandler: NotFoundHandler = (ctx) => errorHandler(new NotFoundError(), ctx);