项目文件夹

文件
wehub-resource-sync 98e40dac97
CLI Smoke Test / smoke-test-linux (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-linux (24) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (20) (push) Has been cancelled
CLI Smoke Test / smoke-test-windows (24) (push) Has been cancelled
Expo App TypeScript typecheck / typecheck (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:40:49 +08:00

96 行
3.4 KiB
TypeScript

import { log } from "@/utils/log";
import { Fastify } from "../types";
import { FastifyError } from "fastify";
export interface EnableErrorHandlersOptions {
skipNotFoundHandler?: boolean;
}
export function enableErrorHandlers(app: Fastify, options: EnableErrorHandlersOptions = {}) {
// Global error handler
app.setErrorHandler(async (error: FastifyError, request, reply) => {
const method = request.method;
const url = request.url;
const userAgent = request.headers['user-agent'] || 'unknown';
const ip = request.ip || 'unknown';
// Log the error with comprehensive context
log({
module: 'fastify-error',
level: 'error',
method,
url,
userAgent,
ip,
statusCode: error.statusCode || 500,
errorCode: error.code,
stack: error.stack
}, `Unhandled error: ${error.message}`);
// Return appropriate error response
const statusCode = error.statusCode || 500;
if (statusCode >= 500) {
// Internal server errors - don't expose details
return reply.code(statusCode).send({
error: 'Internal Server Error',
message: 'An unexpected error occurred',
statusCode
});
} else {
// Client errors - can expose more details
return reply.code(statusCode).send({
error: error.name || 'Error',
message: error.message || 'An error occurred',
statusCode
});
}
});
// Catch-all route for debugging 404s. Skipped when caller will register
// its own (e.g. SPA fallback for self-hosted webapp).
if (!options.skipNotFoundHandler) {
app.setNotFoundHandler((request, reply) => {
log({ module: '404-handler' }, `404 - Method: ${request.method}, Path: ${request.url}, Headers: ${JSON.stringify(request.headers)}`);
reply.code(404).send({ error: 'Not found', path: request.url, method: request.method });
});
}
// Error hook for additional logging
app.addHook('onError', async (request, reply, error) => {
const method = request.method;
const url = request.url;
const duration = (Date.now() - (request.startTime || Date.now())) / 1000;
log({
module: 'fastify-hook-error',
level: 'error',
method,
url,
duration,
statusCode: reply.statusCode || error.statusCode || 500,
errorName: error.name,
errorCode: error.code
}, `Request error: ${error.message}`);
});
// Handle uncaught exceptions in routes
app.addHook('preHandler', async (request, reply) => {
// Store original reply.send to catch errors in response serialization
const originalSend = reply.send.bind(reply);
reply.send = function (payload: any) {
try {
return originalSend(payload);
} catch (error: any) {
log({
module: 'fastify-serialization-error',
level: 'error',
method: request.method,
url: request.url,
stack: error.stack
}, `Response serialization error: ${error.message}`);
throw error;
}
};
});
}