繁体   English   中英

在Firebase onCall云函数上使用try / catch异步/等待内部处理错误

[英]Error handling using try / catch inside async / await on firebase onCall cloud function

我目前正在将此云功能部署到我的Firebase应用程序中,并且将使用Node v8运行时,因此可以使用async / await语法。

我在处理同一功能中可能发生的各种错误时遇到了一些麻烦。

完成后,该函数应接收一个url参数以对该URL进行请求,并在响应主体中抓取一些数据并将其保存到数据库中。 此时,它只是返回与测试目的相同的URL字符串。

到目前为止,这就是我所拥有的:

const functions = require('firebase-functions');
const request = require('request');
const cheerio = require('cheerio');

exports.getDataFromUrl = functions.https.onCall((data) => {

  // PROMISIFIED REQUEST TO USE WITH ASYNC AWAIT
  const promisifiedRequest = function(options) {
    return new Promise((resolve,reject) => {
      request(options, (error, response, body) => {
        if (error) {
          return reject(error);
        }
        return resolve(response);
      });
    });
  };

  // CHECK IF URL IS PRESENT, IF NOT, THROW ERROR
  if (!data.url) {
    throw new functions.https.HttpsError('invalid-argument','The URL parameter was invalid.');
  }

  // URL passed from the client.
  const url = data.url;

    // IIFE ASYNC FUNCTION
    (async function() {

      // TRY BLOCK
      try {

        // REQUEST OPTIONS TO THE URL
        const urlOptions = {
          url: 'https://www.someINEXISTENT.url',
          method: 'GET',
          gzip: true,
          headers: {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36'
          },
          jar: true
        };

        // CREATE RESPONSE AND CHEERIO OBJECT
        let response = null;
        let $ = null;

        // SEND REQUEST TO URL, AND PARSE WITH CHEERIO
        response = await promisifiedRequest(urlOptions);
        $ = cheerio.load(response.body);

      } // TRY BLOCK - END

      // CATCH BLOCK
      catch (error) {
        console.log('Caught an error: ' + error);
        throw new functions.https.HttpsError('unknown', error.message, error);
      }

      console.log('End of async function...');

    })()

  return {
    yourUrl : url
  };

});

我的第一个错误案例是在URL无效时发生的,它工作正常。 当我抛出以下错误时,执行停止:

throw new functions.https.HttpsError('invalid-argument','URL invalid.');

据我了解,有必要抛出此HttpsError以便能够赶上客户端。 而且有效。 发生这种情况时,我会在客户端收到此错误。

在此处输入图片说明

我的问题是第二种类型的错误,应该由async函数中try / catch语句捕获 例如,当我尝试请求不存在的网址时,就会发生该错误。

这是怎么回事(下图):

catch块已激活,我可以在功能控制台上看到`console.log(),但是不知何故它不会引发错误,并且即使“我没有抛出catch块也将其扔到异步函数中”从捕获块里面钻研 我的客户端代码根本没有收到此错误。 从我的客户的角度来看,该功能完整无误。

在此处输入图片说明

错误:

错误:(节点:5160)UnhandledPromiseRejectionWarning:未处理的承诺拒绝。 该错误是由于在没有catch块的情况下抛出异步函数而引起的,或者是由于拒绝了未经.catch()处理的诺言而引起的。 (拒绝ID:1)

我尝试添加和外部try/catch块。 并且在异步IIFE之后也使用.catch()将错误抛出到异步函数之外,但是并不能解决问题。

我究竟做错了什么?

...但是以某种方式不会引发错误...

那是因为没有东西使用async函数创建的promise,而throw被拒绝。 承诺的规则之一是:您必须处理承诺被拒绝或将结果返回给其他将要发生的事情。

functions.https.onCall允许您返回promise ,所以我将回调设为async函数,而不是使用异步IIFE。 您无法同步提供结果或引发错误,因为您正在处理异步操作。

这些方面的内容(可能需要调整,请参阅***注释):

const functions = require('firebase-functions');
const request = require('request');
const cheerio = require('cheerio');

// *** No reason to define this within `onCall`'s handler
const promisifiedRequest = function(options) {
  return new Promise((resolve,reject) => {
    request(options, (error, response, body) => {
      if (error) {
        return reject(error);
      }
      return resolve(response);
    });
  });
};

exports.getDataFromUrl = functions.https.onCall(async (data) => { // *** Make it async, since `onCall` allows you to return a promise

  // CHECK IF URL IS PRESENT, IF NOT, THROW ERROR
  if (!data.url) {
    throw new functions.https.HttpsError('invalid-argument','The URL parameter was invalid.');
  }

  // URL passed from the client.
  const url = data.url;

  // *** No need for try/catch unless you want to change the error
  // *** If you do, though, add it back and use `throw` in the `catch` block (as you did originally).
  // *** That will make the promise this async function returns reject.

  // REQUEST OPTIONS TO THE URL
  const urlOptions = {
    url: 'https://www.someINEXISTENT.url',
    method: 'GET',
    gzip: true,
    headers: {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.96 Safari/537.36'
    },
    jar: true
  };

  // CREATE RESPONSE AND CHEERIO OBJECT
  let response = null;
  let $ = null;

  // SEND REQUEST TO URL, AND PARSE WITH CHEERIO
  response = await promisifiedRequest(urlOptions);
  $ = cheerio.load(response.body);

  // *** Do you really want to return the URL? Not something from the body of what you requested?
  return {
    yourUrl : url
  };
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM