Gernar
Frontend DeveloperNode.js, Express и middleware

Интервью-вопрос

Что такое параметр next в middleware

next в middleware передает управление следующему обработчику или в обработчик ошибок. Практический риск в том, что один неверный вызов может подвесить запрос, отправить ответ дважды или скрыть ошибку.

Добавлен
Редакция

Подготовьте короткий ответ и пару деталей на случай уточняющих вопросов.

🐰0
🥚0

Мини-квиз

Проверка перед разбором

Несколько быстрых вопросов перед разбором. Так проще поймать места, которые только кажутся понятными.

Вопрос 1 из 50 правильно

Как лучше объяснить next() на интервью?

Вы сейчас хотите дать короткое и точное определение без лишней теории.

Варианты ответа

Разбор

Разобраться, а не зазубрить

Дальше разбираем суть, типичные уточнения и места, где легко сказать лишнее или перепутать термины.

Базовая идея

Обычно этот вопрос про middleware в стиле Express. Middleware получает запрос, ответ и функцию next. Обработчик может сделать проверку, записать лог, добавить данные к запросу, а потом передать управление дальше.

Коротко можно ответить так:

next() говорит фреймворку, что текущий middleware закончил работу и можно выполнять следующий обработчик. next(err) передает ошибку в специальный обработчик ошибок.

Не ограничивайтесь фразой про продолжение цепочки. Добавьте, что без next() или явного ответа клиенту запрос не завершится нормально.

Что происходит в цепочке

Порядок выполнения зависит от порядка регистрации middleware. Вам это пригодится в BFF, dev server, SSR-приложении или API-роутах. Например, проверка авторизации должна сработать до бизнес-обработчика, а общий error handler обычно ставят после обычных routes.

app.use((req, res, next) => {
  console.log(req.method, req.url);
  next();
});

app.use((req, res, next) => {
  if (!req.user) {
    return res.status(401).json({ message: 'Unauthorized' });
  }

  next();
});

app.get('/profile', (req, res) => {
  res.json({ profile: req.user.profile });
});

В первом middleware нет ответа клиенту, поэтому нужен next(). Во втором есть развилка: если пользователя нет, ответ уже отправлен и цепочку продолжать нельзя. Если пользователь есть, можно идти дальше.

Как выбрать действие в middleware

У middleware всегда должен быть понятный финал. Он передает управление дальше, завершает ответ или передает ошибку. Если смешать эти варианты, появятся зависшие запросы, двойные ответы и сложные баги в тестах.

Что делать в конце middleware

1Middleware только проверил условие и не должен отвечать клиенту?
Вызовите next(), чтобы цепочка продолжилась.
2Middleware уже отправил ответ, redirect или status с body?
Завершите функцию через return и не вызывайте next().
3Внутри поймали ошибку, которую должен обработать общий error handler?
Передайте ее через next(err).
4Нужно передать данные следующему обработчику?
Положите данные в req, res.locals или контекст фреймворка.

Главная ловушка: next() после ответа

Плохой пример:

app.use((req, res, next) => {
  if (!req.user) {
    res.status(401).json({ message: 'Unauthorized' });
  }

  next();
});

Здесь next() вызовется даже после ответа 401. Следующий обработчик может выполнить приватную логику или попытаться отправить еще один ответ. Лучше выйти из функции сразу после ответа.

app.use((req, res, next) => {
  if (!req.user) {
    return res.status(401).json({ message: 'Unauthorized' });
  }

  next();
});

На интервью можно сказать: return здесь не заменяет next(). Он просто не дает коду ниже выполниться после отправки ответа.

Безопасный поток
  1. 1Проверить условие
  2. 2Либо отправить ответ и выйти через return
  3. 3Либо вызвать next() один раз
  4. 4Ошибку передать через next(err)
Опасный поток
  1. 1Отправить res.send()
  2. 2Продолжить выполнение функции
  3. 3Вызвать next() после ответа
  4. 4Получить второй ответ или лишний обработчик

Ошибки и next(err)

Если middleware не может корректно продолжить работу, ошибку часто передают через next(err). Тогда общий error handler залогирует проблему, выберет статус и вернет единый формат ответа.

app.use(async (req, res, next) => {
  try {
    req.user = await loadUser(req.headers.authorization);
    next();
  } catch (err) {
    next(err);
  }
});

app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({ message: 'Internal server error' });
});

Это лучше, чем вручную собирать разные ответы с ошибками в каждом middleware. Для клиента важен стабильный формат ошибки. Тогда React-код одинаково обработает loading, error и повтор запроса. Но учитывайте конкретный фреймворк и версию. Обработка async ошибок может отличаться, поэтому не говорите, что Express всегда сам все поймает.

Передача данных между middleware

next не стоит использовать как канал данных. В Express аргумент next обычно означает ошибку, поэтому next(user) выглядит как переход в ошибочную ветку, а не как передача пользователя.

Для данных используйте явное место:

app.use(async (req, res, next) => {
  const user = await loadUser(req.headers.authorization);

  req.user = user;
  // или res.locals.user = user;

  next();
});

Практический вывод простой. Следующий обработчик должен понимать, откуда брать данные, а не угадывать смысл аргумента в next. Так код проще тестировать. Еще ниже риск случайно отправить запрос в error handler. Не используйте глобальную переменную для пользователя или токена. При параллельных запросах можно получить race condition и утечку данных между пользователями.

Нюанс про Next.js Middleware

Формулировка может звучать похоже на Next.js, но это другой API. В Next.js Middleware нет callback-параметра next как в Express. Там обычно возвращают NextResponse.next(), NextResponse.redirect() или NextResponse.rewrite().

Если на интервью вопрос задан без фреймворка, безопасная фраза такая:

Если мы говорим про Express-подобный middleware, next это callback для передачи управления дальше. В Next.js Middleware механика другая: мы возвращаем NextResponse.next() или другой ответ.

Так вы покажете, что не смешиваете разные экосистемы и готовы уточнить контекст.

Практический вывод

Сильный ответ должен звучать не как словарное определение, а как правило для кода. В каждом middleware явно выберите один вариант. Продолжить цепочку, завершить ответ или передать ошибку. Не вызывайте next() после ответа и не используйте его для обычных данных.

Для frontend-разработчика это важно в BFF, SSR, мок-серверах, API routes и dev middleware. Ошибка в цепочке может выглядеть как "фронт завис", "логин не работает" или "API иногда отвечает дважды", хотя причина находится в серверном middleware.

Частые ошибки

Где обычно ошибаются

Проверьте формулировки, которые звучат уверенно, но на интервью быстро выдают пробелы.

  1. 1

    Забыть next() в проходном middleware

    Если middleware только логирует или добавляет данные, но не вызывает next(), цепочка остановится. В UI это выглядит как вечный loading, повторные клики по кнопке или таймаут сетевого запроса. Безопаснее сразу решить: этот обработчик завершает ответ сам или передает управление дальше.
  2. 2

    Вызвать next() после отправки ответа

    После res.send(), res.json() или res.redirect() следующий обработчик может попытаться снова изменить ответ. Частый симптом: ошибка про уже отправленные headers. В худшем случае приватный обработчик выполнится после 401 и сделает лишний запрос к данным. После завершения ответа обычно пишут return и не вызывают next().
  3. 3

    Путать return и next()

    return останавливает текущую функцию, но не запускает следующий middleware. next() передает управление дальше. На интервью лучше прямо сказать эту разницу. Ее часто проверяют на коде с авторизацией.
  4. 4

    Передавать данные как next(user)

    В Express аргумент next обычно означает ошибку, поэтому next(user) может отправить запрос в error handler. Для данных используйте req.user, res.locals.user или другой явный контейнер. Так поведение будет понятно и следующему middleware, и тестам.
  5. 5

    Не учитывать async ошибки

    В асинхронном middleware ошибка из await должна попасть в обработчик ошибок. В зависимости от версии и обвязки Express может понадобиться try/catch с next(err). Иначе фронтенд может получить HTML вместо JSON, неверный статус или зависший запрос, а UI покажет неправильный error state.

Follow-up

Что могут спросить дальше

Короткие ответы на вопросы, которыми проверяют понимание middleware, ошибок и контроля потока.

Живые ответы

Видео с похожим вопросом

Если найдем публичные интервью с таким вопросом, добавим их сюда. Их удобно смотреть после теории, чтобы свериться с живыми ответами.

Пока видео нет. Когда появятся подходящие публичные интервью, добавим их в этот блок, чтобы можно было сравнить разбор с тем, как отвечают реальные кандидаты.

Содержание