import { ErrorRequestHandler, Request, Response } from "express"; import createHttpError, { HttpError } from "http-errors"; import { createLogger } from '../lib/logger'; import { NgitLocals } from "../types/NgitLocals"; import { failedRequestCounter } from "../lib/metricsCounters"; import { SupportedRoutes } from "../types/enums/SupportedRoutes"; const consoleLog = createLogger("server:server"); /** * Router koji se zadnji poziva, a koji sastavlja odgovor u slučaju greške * @param err * @param req * @param res * @param next */ export const errorRouter:ErrorRequestHandler = async (err:HttpError, req, res, next) => { const requestPath = req.path as SupportedRoutes; // kako je ovaj error handler dosta složen, moguće je da negdje baci grešku // > zato je zamotan u try-catch // > na taj način osiguravam da neće srušiti cijeli proces try { let { name:errorLogName, message:errorLogText } = err; let responseBody:string = ""; switch(err.status) { case 400: responseBody = 'bad request'; break; case 401: responseBody = 'unauthorized'; break; case 403: responseBody = 'forbidden'; break; case 404: consoleLog(`page not found ${req.method} ${requestPath}`) responseBody = 'page not found'; errorLogText = `page ${requestPath} not found`; break; case 500: responseBody = "internal server error"; errorLogText = err.message; break; default: responseBody = err.name; errorLogText = `err.status=${err.status};err.name=${err.name};err.message=${err.message}`; } consoleLog(`${errorLogName}:${errorLogText}`); // `headersSent` će biti TRUE ako je router kod kojeg se dogodila greška već poslao header-e // > ako ih probam ponovo postaviti, to će baciti grešku ... a to ovdje mogu izbjeći if(!res.headersSent) { res.status(err.status); res.setHeader('Content-Type', "text/html"); res.end(responseBody); } else { // AKO nije pozvan `end` - pozovi ga i završi obradu zahtjeva // ... u suprotnom će konekcija ostati otvorena do timeout-a if(!res.writableEnded) { res.end(); } } } catch(ex:any) { // ovu grešku će obraditi `finalErrorRouter` next(createHttpError(500, ex)); } // ne mogu dopustiti da prometheus client sruši server try { failedRequestCounter.inc({ path: requestPath, status: err.status }); (res.locals as NgitLocals).stopPrometheusTimer({ path: req.path, status: err.status }); } catch(ex:any) { console.error(ex); } };