Обработка ошибок
Если маршрут не найден, Hono отвечает текстом 404 Not Found, а если в коде возникло исключение — текстом Internal Server Error с кодом 500. Для API это неудобно: клиент ждёт JSON. Hono позволяет заменить оба ответа и выбрасывать ошибки с нужным кодом прямо из обработчика.
Неизвестный адрес
В src/index.ts, после подключения групп маршрутов, добавьте:
// src/index.ts
app.notFound((c) => {
return c.json({ error: `Адрес ${c.req.path} не найден` }, 404)
})Откройте http://localhost:3000/nothing — придёт JSON {"error":"Адрес /nothing не найден"} с кодом 404.
HTTPException
Чтобы прервать обработку с понятным кодом, выбросьте HTTPException:
// src/routes/posts.ts
import { HTTPException } from 'hono/http-exception'
posts.get('/:id', (c) => {
const post = allPosts.find((p) => p.id === Number(c.req.param('id')))
if (!post) {
throw new HTTPException(404, { message: 'Статья не найдена' })
}
return c.json(post)
})Здесь allPosts — массив статей из прошлых уроков. Запрос /posts/99 вернёт код 404 и текст «Статья не найдена». Исключение удобно выбрасывать из вспомогательных функций и middleware, где вернуть ответ через return нельзя.
Общий обработчик ошибок
app.onError() получает каждую ошибку, которую не перехватил обработчик:
// src/index.ts
import { HTTPException } from 'hono/http-exception'
app.onError((err, c) => {
if (err instanceof HTTPException) {
return c.json({ error: err.message }, err.status)
}
console.error(err)
return c.json({ error: 'Внутренняя ошибка сервера' }, 500)
})Теперь /posts/99 вернёт JSON {"error":"Статья не найдена"} с кодом 404. Любая другая ошибка, например опечатка в коде, запишется в терминал, а клиент получит короткое сообщение с кодом 500.
Где что срабатывает
| Ситуация | Кто отвечает |
|---|---|
| нет подходящего маршрута | app.notFound() |
throw new HTTPException(...) | app.onError() |
| любая другая ошибка в коде | app.onError() |
| ошибка проверки zod | сам валидатор, код 400 |
Обработчики notFound и onError задают у главного приложения в src/index.ts: тогда они работают и для групп, подключённых через app.route().
Проверка
curl -i http://localhost:3000/posts/99В ответе будет строка HTTP/1.1 404 Not Found и JSON с сообщением.
Частая ошибка
В onError отдают клиенту текст любой ошибки:
// src/index.ts
app.onError((err, c) => c.json({ error: err.message }, 500))Так наружу попадают внутренние подробности: текст SQL-запроса, пути к файлам, имена таблиц. Показывайте клиенту только сообщения HTTPException, которые вы написали сами, а остальное пишите в журнал.