Почему я получаю ошибку «502 Gateway» из приложения NextJS, размещенного на Firebase, только для запросов POST?

#firebase #google-cloud-functions #next.js #firebase-hosting

#firebase #google-cloud-функции #next.js #firebase-хостинг

Вопрос:

Я начал создавать API с использованием NextJS framework. Я хочу, чтобы оно было размещено на Firebase (хостинг и функции). Все работает, пока я отправляю только запросы GET. Когда я отправляю POST-запрос, я получаю сообщение об ошибке «502 Bad Gateway».

Это очень просто воспроизвести. Вам просто нужно загрузить и развернуть пример, предоставленный командой разработчиков NextJS.

  • создайте новый проект в Firebase console

  • установите пример «с хостингом Firebase«

  • измените название проекта в .файл firebaserc (строка 3)

  • создайте папку «api» в папке «страницы»

  • создайте файл «hello.js « в папке «api» и добавьте следующий фрагмент

     export default async (req, res) => {
      const {
        body,
        method
      } = req;
    
      console.log("method :>> ", method);
      console.log("body :>> ", body);
    
      switch (method) {
      case "POST":
        res.status(200).end(`Method ${method} supported!`);
        break;
      default:
        res.setHeader("Allow", ["POST"]);
        res.status(405).end(`Method ${method} Not Allowed`);
      }
    };
    
      
  • разверните приложение

  • отправьте запрос GET на «https: // [project-name].web.app / api / hello» и посмотрите, как это работает

  • отправьте запрос POST на «https: // [project-name].web.app / api / hello» и увидите, что он не работает

У вас такая же ошибка, как у меня?

Я потратил 2 дня на чтение статей, просмотр видео и пробование разных конфигураций. Вы даже можете обновить функции firebaseFunctions, чтобы добавить a console.log и увидеть, что запрос POST перехватывается облачной функцией Firebase, но сервер NextJS не передает его в наш API, как для запроса GET. Это выходит за рамки моих навыков…

Ниже вывод, который у вас должен быть. На запрос POST следует ответить 200 - Method POST is supported! .

введите описание изображения здесь

Комментарии:

1. У меня есть другой проект, использующий ExpressJS, и я никогда не сталкивался с этой проблемой.

2. Я склонен думать, что это вызвано res.status(204).end(``Method ${method} supported!``); не чем иным. Попробуйте res.status(204).end(); вместо этого.

3. @samthecodingman Если вы попробуете, вы увидите, что в облачных функциях Firebase нет журнала. Это означает, что метод не вызывается. Я обновил фрагмент (спасибо за помощь!)

Ответ №1:

Это было настоящей проблемой для отслеживания, но, покопавшись некоторое время, я обнаружил, что одна и та же проблема возникает для запросов PUT и PATCH. Что предполагает, что это как-то связано с телом запроса. К сожалению, узнав об этом, я наткнулся на ветку проблемы # 7960, где они обнаружили ту же проблему.

Проще говоря, тело запроса обрабатывается один раз, https.onRequest() а затем nextjsHandle() пытается проанализировать его снова. Поскольку тело уже было обработано, raw-body модуль (внутри nextjsHandle() ) бесконечно ожидает 'data' событий, которые никогда не наступят.

В настоящее время нет способа отключить синтаксический анализ тела, выполняемый https.onRequest() , поэтому он должен быть отключен на next.js конец. К сожалению, нет глобального выключателя для синтаксического анализа тела, который можно добавить, next.config.js и это должно быть сделано для каждого маршрута API (файлов pages/api ) (который может измениться, если будет добавлено предлагаемое исправление в PR # 16169).

Чтобы отключить синтаксический анализ тела для данного маршрута, вы добавляете следующее в файл маршрута

 export const config = {
  api: {
    // disables call to body parsing module
    bodyParser: false,
  }
};
  

Однако, как упоминалось в выпуске # 7960 от @rscotten, вы также можете захотеть использовать next dev его при разработке своего приложения, поэтому вам нужно включить его во время использования next dev , но отключить во время развертывания. Это можно сделать с помощью

 export const config = {
  api: {
    // disables call to body parsing module while deployed
    bodyParser: process.env.NODE_ENV !== 'production',
  }
};
  

Применение этих изменений к hello.js дает:

 export default async (req, res) => {
  const {
    body,
    method
  } = req;

  console.log("method :>> ", method);
  console.log("body :>> ", body);

  switch (method) {
  case "POST":
    res.status(200).end(`Method ${method} supported!`);
    break;
  default:
    res.setHeader("Allow", ["POST"]);
    res.status(405).end(`Method ${method} Not Allowed`);
  }
};

export const config = {
  api: {
    // disable nextjs's body parser while deployed
    // (as body parsing is handled by `https.onRequest()`),
    // but enable it for local development using `next dev`
    bodyParser: process.env.NODE_ENV !== 'production',
  }
};
  

Комментарии:

1. Я искал неправильный путь. У меня уже была такая же проблема с приложением ExpressJS, но ошибка, которую я получил, была ясной, я мог быстро ее решить. Я начал заменять NextJS на ExpressJS, когда увидел ваш ответ. Большое спасибо, Сэм, за вашу помощь!

2. Также должна быть проблема с конфигурацией хостинга Firebase. Потому что теперь у меня «502 Bad Gateway» при использовании Puppeteer в облачных функциях Firebase. Метод «goto» не завершается. Локально все работает нормально, и в другом проекте я могу использовать Puppeteer без каких-либо проблем. Разница в том, что я перенаправляю не все запросы на сервер Next / Express, а только те, которые находятся в разделе «/ api / **». Я расследую это…

3. Я был неправ, но вместо удаления моего комментария давайте сохраним историю того, что произошло после проблемы со шлюзом сервера Express / Next. Я использую Puppeteer в API, который я предоставляю через сервер. Я все еще получал 502 - Bad Gateway сообщение об ошибке, потому что после того, как Puppeteer загрузил страницу, она ждала слишком долго. Я просто удаляю «дополнительный» waitForNavigation вызов. Локально с этим проблем не было, но на Firebase это мешало продолжению моего скрипта.