82 lines
2.3 KiB
JavaScript
82 lines
2.3 KiB
JavaScript
/**
|
|
* Централизованный обработчик ошибок
|
|
*/
|
|
|
|
const promClient = require('prom-client');
|
|
|
|
// Метрики
|
|
const http304 = new promClient.Counter({ name: 'http_304_total', help: 'HTTP 304 responses' });
|
|
const http412 = new promClient.Counter({ name: 'http_412_total', help: 'HTTP 412 responses' });
|
|
const http423 = new promClient.Counter({ name: 'http_423_total', help: 'HTTP 423 responses' });
|
|
|
|
/**
|
|
* Отправить успешный ответ с метаданными
|
|
*/
|
|
function sendOk(res, meta) {
|
|
if (meta?.etag) res.set('ETag', String(meta.etag));
|
|
if (meta?.lastModified) res.set('Last-Modified', new Date(meta.lastModified).toUTCString());
|
|
if (typeof meta?.contentLength === 'number') res.set('Content-Length-Source', String(meta.contentLength));
|
|
return res.json({
|
|
ok: true,
|
|
etag: meta?.etag || null,
|
|
lastModified: meta?.lastModified || null,
|
|
contentLength: meta?.contentLength ?? null
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Отправить ошибку
|
|
*/
|
|
function sendError(res, status, message, code, details) {
|
|
const requestId = res.req?.id;
|
|
try {
|
|
if (status === 304) http304.inc();
|
|
if (status === 412) http412.inc();
|
|
if (status === 423) http423.inc();
|
|
} catch {}
|
|
return res.status(status).json({ code, message, details, requestId });
|
|
}
|
|
|
|
/**
|
|
* Проверить If-None-Match заголовок
|
|
*/
|
|
function checkIfNoneMatch(req, res, etag) {
|
|
const inm = req.headers && (req.headers['if-none-match'] || req.headers['If-None-Match']);
|
|
if (inm && etag && String(inm) === String(etag)) {
|
|
try { http304.inc(); } catch {}
|
|
res.status(304).end();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Централизованный error handler middleware
|
|
*/
|
|
function errorHandler(err, req, res, next) {
|
|
const status = typeof err?.status === 'number' ? err.status : 500;
|
|
const code = err?.code || 'E_INTERNAL';
|
|
const message = status === 500 && process.env.NODE_ENV === 'production'
|
|
? 'Internal Server Error'
|
|
: (err?.message || 'Error');
|
|
const details = err?.details;
|
|
const requestId = req?.id;
|
|
|
|
try {
|
|
req.log?.error({ err, code, requestId }, 'request error');
|
|
} catch {}
|
|
|
|
res.status(status).json({ code, message, details, requestId });
|
|
}
|
|
|
|
module.exports = {
|
|
sendOk,
|
|
sendError,
|
|
checkIfNoneMatch,
|
|
errorHandler,
|
|
http304,
|
|
http412,
|
|
http423,
|
|
};
|
|
|