Firebase «Unhandled Rejection» и «Не удается установить заголовки после их установки» JavaScript error - PullRequest
0 голосов
/ 01 апреля 2020

Во-первых, обратите внимание, что я очень очень плохо знаком с JS и программирую в целом:)

Желаемое поведение: я написал следующую JS HTTPS Firebase-функцию, которая принимает параметр запроса locationId, он выполняет вызов API GET и сохраняет ответ обратно в Firebase. Код корректно сохраняет данные в Firebase по желанию. Я сталкивался с подобными проблемами, но я изо всех сил пытаюсь приспособить эти решения к моей конкретной проблеме c ниже. Из того, что я вижу, я отправляю ответ только один раз.

Specifi c ошибка: Ниже приведен вывод консоли

Невозможно установить заголовки после их отправки в клиент

необработанный отказ

enter image description here

Моя функция:

exports.doshiiGetMenuForOnboardedVenue = functions.https.onRequest((req, res) => {

  // Forbidding PUT requests.
  if (req.method === 'PUT') {
    return res.status(403).send('Forbidden!');
  }

  cors(req, res, () => {

    const locationId = req.query.locationId;

    console.log('locationId', locationId);

    if (locationId){

      console.log('locationId', locationId);

      var token = jwttoken();

      const options = {
          headers: {
            'content-type': 'application/json',
            'authorization': 'Bearer ' + token}
        };

        const uri = 'https://sandbox.doshii.co/partner/v3/locations/' + locationId + '/menu?lastVersion=:lastVersion&filtered=true'

        axios.get(uri, options)
          .then(response => {

             return admin.database().ref(`/venue-menus/${locationId}/`).set(response.data)
             .then(response => {
               return res.status(200).send(locationId)
             })
             .catch(err => {
               return res.status(500).send({error: err})
             })

          })
          .then(response => {
                    return res.status(200).send(locationId)
            })
          .catch(err => {
            return res.status(500).send({error: err})
          })//end axios

    } else {

      return res.status(500).send({error: 'locationId missing'})

    }//end if-else (!locationId)

  })//end cors

});

1 Ответ

1 голос
/ 01 апреля 2020

Выровняв вложенные обещания, вы можете увидеть, что ваш код выполняет следующие инструкции (когда вызов axios не выдает ошибку):

admin.database().ref(`/venue-menus/${locationId}/`).set(response.data))
  .then(response => res.status(200).send(locationId))
  .catch(err => res.status(500).send({error: err})
  .then(response => res.status(200).send(locationId)) // this line is always called after either of the above.
  .catch(err => res.status(500).send({error: err})

Как правило, если только требуется, вы не должны вкладывать обещания с их собственными обработчиками then() и catch(), так как это приведет к странным эффектам, подобным этому.

Кроме того, если ваш код требует использования сообщений //end axios или //end cors , вы должны выровнять свой код, чтобы он имел смысл без этих сообщений.

Адаптация вашего кода к «быстрому отказу», исправление ваших ответов API и надлежащее скрытие трассировок стека ошибок дает:

const cors = require('cors')({
  origin: true,
  methods: ["GET"]
});


exports.doshiiGetMenuForOnboardedVenue = functions.https.onRequest((req, res) => {
  cors(req, res, (err) => { // note: cors will handle OPTIONS method

    if (err) {
      // note: log full error at ERROR message level
      console.error('Internal CORS error:', err);
      // note: return only generic status message to client
      return res.status(500).json({error: 'Internal Server Error'});
    }

    // Forbidding anything but GET requests.
    if (req.method !== 'GET') {
      // 405 METHOD_NOT_ALLOWED
      return res.status(405)
        .set('Allow', 'GET')
        .json({error: 'Not Allowed!'});
    }

    const locationId = req.query.locationId;

    console.log('locationId', locationId);

    if (!locationId) {
      // 400 BAD_REQUEST
      return res.status(400).json({error: 'locationId missing'})
    }

    var token = jwttoken();

    const options = {
        headers: {
          'content-type': 'application/json',
          'authorization': 'Bearer ' + token
        }
      };

    // note: Don't forget to enable billing for third-party APIs!
    const uri = 'https://sandbox.doshii.co/partner/v3/locations/' + locationId + '/menu?lastVersion=:lastVersion&filtered=true'

    axios.get(uri, options)
      .then(response => admin.database().ref(`/venue-menus/${locationId}/`).set(response.data))
      .then(() => {
        // note: as locationId was already sent by the client, send new/useful
        // information back or nothing but the right status code
        res.status(200).json({ ref: `/venue-menus/${locationId}/` });
      })
      .catch(err => {
        // note: log full error at ERROR message level
        console.error('Failed to retrieve/save API data:', err);
        // note: return only message to client
        res.status(500).json({error: err.message || 'Internal Server Error'});
      });
  });
});
...