Files
vat-api.eu/node_modules/@nuxt/nitro-server/dist/runtime/handlers/error.mjs
2026-02-13 22:02:30 +01:00

78 lines
3.6 KiB
JavaScript

import { joinURL, withQuery, withoutBase } from "ufo";
import { appendResponseHeader, getRequestHeaders, send, setResponseHeader, setResponseHeaders, setResponseStatus } from "h3";
import { useNitroApp, useRuntimeConfig } from "nitropack/runtime";
import { isJsonRequest } from "../utils/error.mjs";
import { generateErrorOverlayHTML } from "../utils/dev.mjs";
export default (async function errorhandler(error, event, { defaultHandler }) {
if (event.handled || isJsonRequest(event)) {
// let Nitro handle JSON errors
return;
}
// invoke default Nitro error handler (which will log appropriately if required)
const defaultRes = await defaultHandler(error, event, { json: true });
// let Nitro handle redirect if appropriate
const status = error.status || error.statusCode || 500;
if (status === 404 && defaultRes.status === 302) {
setResponseHeaders(event, defaultRes.headers);
setResponseStatus(event, defaultRes.status, defaultRes.statusText);
return send(event, JSON.stringify(defaultRes.body, null, 2));
}
if (import.meta.dev && typeof defaultRes.body !== "string" && Array.isArray(defaultRes.body.stack)) {
// normalize to string format expected by nuxt `error.vue`
defaultRes.body.stack = defaultRes.body.stack.join("\n");
}
const errorObject = defaultRes.body;
// remove proto/hostname/port from URL
const url = new URL(errorObject.url);
errorObject.url = withoutBase(url.pathname, useRuntimeConfig(event).app.baseURL) + url.search + url.hash;
// add default server message (keep sanitized for unhandled errors)
errorObject.message = error.unhandled ? errorObject.message || "Server Error" : error.message || errorObject.message || "Server Error";
// we will be rendering this error internally so we can pass along the error.data safely
errorObject.data ||= error.data;
errorObject.statusText ||= error.statusText || error.statusMessage;
delete defaultRes.headers["content-type"];
delete defaultRes.headers["content-security-policy"];
setResponseHeaders(event, defaultRes.headers);
// Access request headers
const reqHeaders = getRequestHeaders(event);
// Detect to avoid recursion in SSR rendering of errors
const isRenderingError = event.path.startsWith("/__nuxt_error") || !!reqHeaders["x-nuxt-error"];
// HTML response (via SSR)
const res = isRenderingError ? null : await useNitroApp().localFetch(withQuery(joinURL(useRuntimeConfig(event).app.baseURL, "/__nuxt_error"), errorObject), {
headers: {
...reqHeaders,
"x-nuxt-error": "true"
},
redirect: "manual"
}).catch(() => null);
if (event.handled) {
return;
}
// Fallback to static rendered error page
if (!res) {
const { template } = await import("../templates/error-500");
if (import.meta.dev) {
// TODO: Support `message` in template
errorObject.description = errorObject.message;
}
setResponseHeader(event, "Content-Type", "text/html;charset=UTF-8");
return send(event, template(errorObject));
}
const html = await res.text();
for (const [header, value] of res.headers.entries()) {
if (header === "set-cookie") {
appendResponseHeader(event, header, value);
continue;
}
setResponseHeader(event, header, value);
}
setResponseStatus(event, res.status && res.status !== 200 ? res.status : defaultRes.status, res.statusText || defaultRes.statusText);
if (import.meta.dev && !import.meta.test && typeof html === "string") {
const prettyResponse = await defaultHandler(error, event, { json: false });
if (typeof prettyResponse.body === "string") {
return send(event, html.replace("</body>", `${generateErrorOverlayHTML(prettyResponse.body, { startMinimized: 300 <= status && status < 500 })}</body>`));
}
}
return send(event, html);
});