Фреймворк Fresh предоставляет современный подход к разработке веб-приложений на JavaScript и Deno, сочетая высокую производительность с минимальной сложностью. Одним из ключевых аспектов стабильного приложения является эффективная система отслеживания ошибок. В Fresh она строится на сочетании встроенных инструментов и сторонних решений.
Каждый маршрут в Fresh представлен компонентом, экспортирующим
функцию handler, которая может содержать обработку
HTTP-запросов. Для базовой обработки ошибок применяется конструкция
try...catch.
export const handler = {
async GET(req, ctx) {
try {
const data = await fetchSomeData();
return new Response(JSON.stringify(data), { status: 200 });
} catch (err) {
console.error("Ошибка запроса:", err);
return new Response("Внутренняя ошибка сервера", { status: 500 });
}
}
};
Особенности:
console.error сохраняет стек ошибки в
серверных логах Deno.Fresh позволяет использовать middleware для глобального
перехвата ошибок. С помощью функции app.use можно
внедрить обработку всех необработанных исключений.
import { h } from "preact";
import { createHandler } from "$fresh/server.ts";
function errorHandler(ctx, next) {
try {
return next();
} catch (err) {
console.error("Глобальная ошибка:", err);
return new Response("Произошла ошибка", { status: 500 });
}
}
const handler = createHandler({
middleware: [errorHandler]
});
Преимущества глобальной обработки:
Fresh поддерживает создание кастомных страниц ошибок, которые автоматически рендерятся при возникновении исключений на уровне компонентов.
// routes/_500.tsx
import { h } from "preact";
export default function InternalError() {
return (
<div>
<h1>500 — Внутренняя ошибка сервера</h1>
<p>Что-то пошло не так. Попробуйте позже.</p>
</div>
);
}
Ключевые моменты:
_500.tsx автоматически отображается при ошибках
500._404.tsx для страниц не
найдено.Для продакшн-приложений критично использовать внешние сервисы отслеживания ошибок:
Пример интеграции с Sentry:
import * as Sentry from "@sentry/browser";
Sentry.init({ dsn: DENO_ENV_SENTRY_DSN });
export const handler = {
async GET(req, ctx) {
try {
const data = await fetchSomeData();
return new Response(JSON.stringify(data));
} catch (err) {
Sentry.captureException(err);
return new Response("Внутренняя ошибка сервера", { status: 500 });
}
}
};
Преимущества интеграции:
Эффективное отслеживание ошибок невозможно без структурированного логирования:
timestamp,
level, message, stack.requestId), что облегчает поиск причин ошибок.Пример структурированного логирования:
function logError(err, reqId) {
console.error(JSON.stringify({
timestamp: new Date().toISOString(),
level: "error",
requestId: reqId,
message: err.message,
stack: err.stack
}));
}
В Fresh большое внимание уделяется асинхронным операциям, поэтому важно правильно обрабатывать ошибки промисов:
try {
const result = await fetchData();
} catch (err) {
logError(err, ctx.requestId);
}
Использование Promise.allSettled позволяет безопасно
обрабатывать несколько параллельных запросов без остановки всего
маршрута при ошибке одного:
const results = await Promise.allSettled([fetchData1(), fetchData2()]);
results.forEach((res) => {
if (res.status === "rejected") {
console.error("Ошибка асинхронного запроса:", res.reason);
}
});
Для стабильности приложения важно покрывать обработку ошибок юнит- и интеграционными тестами:
Deno.test с моками fetch-запросов.Пример теста:
Deno.test("Маршрут GET возвращает 500 при ошибке", async () => {
const resp = await handler.GET(new Request("http://localhost/test"));
if (resp.status !== 500) throw new Error("Ожидался статус 500");
});
Эффективное отслеживание ошибок в Fresh строится на нескольких уровнях: обработка на уровне маршрутов, глобальный middleware, кастомные страницы ошибок, интеграция с системами мониторинга и структурированное логирование. Этот комплексный подход обеспечивает высокую стабильность и предсказуемость поведения приложений.