Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Хуки

Хук — функция, которую Fastify вызывает на определённом этапе жизни запроса или приложения. Хуки заменяют middleware из других фреймворков: в них проверяют доступ, добавляют заголовки, пишут логи.

Этапы запроса

ХукКогда вызываетсяПример задачи
onRequestСразу после получения запросаЗасечь время, проверить токен
preValidationПеред проверкой схемыПодготовить данные
preHandlerПеред обработчиком маршрутаПроверить права
onSendПеред отправкой ответаИзменить ответ, добавить заголовок
onResponseПосле отправки ответаЗаписать статистику

Хуки приложения: onReady — после загрузки всех плагинов, onClose — при остановке сервера.

onRequest

Добавьте хук в плагин src/plugins/timing.js из прошлого урока:

// src/plugins/timing.js
import fp from 'fastify-plugin';
 
async function timing(app) {
  app.decorateRequest('startTime', 0);
 
  app.addHook('onRequest', async (request) => {
    request.startTime = Date.now();
  });
}
 
export default fp(timing);

Теперь у каждого запроса в request.startTime записано время его начала.

onSend

Хук onSend получает третий аргумент — готовое тело ответа. Добавьте его в тот же плагин:

// src/plugins/timing.js
app.addHook('onSend', async (request, reply, payload) => {
  reply.header('x-response-time', `${Date.now() - request.startTime}ms`);
  return payload;
});

curl -i http://localhost:3000/posts покажет заголовок x-response-time: 2ms. Хук обязан вернуть payload — то, что он вернёт, и уйдёт клиенту.

Хук одного маршрута

Хук можно повесить не на всё приложение, а на один маршрут — в его опциях:

// src/routes/posts.js
async function checkAdminHeader(request, reply) {
  if (request.headers['x-admin'] !== 'yes') {
    return reply.code(403).send({ error: 'Доступ запрещён' });
  }
}
 
app.delete('/posts/:id', { preHandler: checkAdminHeader }, async (request, reply) => {
  return reply.code(204).send();
});

DELETE /posts/1 без заголовка x-admin: yes вернёт 403, и обработчик не выполнится. Настоящую проверку через токен покажем в уроке об авторизации.

onClose

onClose вызывается при app.close() — там освобождают ресурсы:

// src/plugins/timing.js
app.addHook('onClose', async () => {
  app.log.info('Сервер останавливается');
});

При остановке через app.close() в логе появится эта строка. В уроке о базе данных здесь будет закрываться соединение.

Область действия

Хук, добавленный в плагине без fastify-plugin, действует только на маршруты этого плагина. Так можно включить проверку для одной группы маршрутов.

Частая ошибка

Если хук отправил ответ через reply.send(), но не вернул reply, Fastify продолжит обработку и вызовет обработчик маршрута. В асинхронном хуке пишите return reply.code(403).send(...), как в примере выше, или бросайте ошибку через throw.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.