Javascript 在firebase onCall云函数上使用异步/等待内部的try/catch进行错误处理
我目前正在将此云功能部署到我的firebase应用程序中,并且我将使用Node v8运行时,因此我可以使用async/await语法 我在处理同一函数中可能出现的各种错误时遇到了一些问题 完成后,函数应接收一个url参数,以请求该url,从响应正文中获取一些数据,并将其保存到数据库中。此时,它只是返回它为测试目的而收到的相同url字符串 到目前为止,我的情况如下:Javascript 在firebase onCall云函数上使用异步/等待内部的try/catch进行错误处理,javascript,firebase,async-await,try-catch,google-cloud-functions,Javascript,Firebase,Async Await,Try Catch,Google Cloud Functions,我目前正在将此云功能部署到我的firebase应用程序中,并且我将使用Node v8运行时,因此我可以使用async/await语法 我在处理同一函数中可能出现的各种错误时遇到了一些问题 完成后,函数应接收一个url参数,以请求该url,从响应正文中获取一些数据,并将其保存到数据库中。此时,它只是返回它为测试目的而收到的相同url字符串 到目前为止,我的情况如下: const functions = require('firebase-functions'); const request = r
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无效时发生)运行正常。当我抛出以下错误时,执行停止:
抛出新函数.https.HttpsError('invalid-argument','URL invalid')代码>
据我所知,需要抛出这个HttpsError
,以便能够了解客户机。它是有效的。我在客户端上得到这个错误,当它发生时
我的问题是第二类错误,应该由我的异步函数中的try/catch语句捕获。例如,当我试图请求一个不存在的url时,就会发生这个错误
发生的情况如下(下图):
catch块被激活了,我可以在我的函数控制台上看到`console.log(),但不知怎么的,它没有抛出错误,它抱怨“在没有catch块的异步函数中抛出”,即使我是从catch块中抛出它。我的客户端代码根本没有收到这个错误。从我的客户的角度来看,函数完成时没有任何错误
错误:
错误:(节点:5160)未处理的PromisejectionWarning:未处理的承诺
拒绝。此错误源于在异步
F未设置挡块的行为,或拒绝不符合要求的承诺
用.catch()处理。(拒绝id:1)
我已经尝试添加和外部try/catch
块。还可以在异步IIFE之后使用.catch()
将错误抛出异步函数之外,但这并没有解决问题
我做错了什么
…但不知怎的,它没有抛出错误
这是因为没有任何东西使用async
函数创建的承诺,该承诺被throw
拒绝。承诺的规则之一是:你必须处理承诺被拒绝的情况,或者将结果返回给其他可能的人
functions.https.onCall
允许您这样做,因此我将使回调成为一个async
函数,而不是使用异步IIFE。您无法同步提供结果或抛出错误,因为您正在处理异步操作
以下内容(可能需要调整,请参见***
注释):
如果要显示错误消息的文本,请将其复制到问题本身,而不是添加屏幕截图。截图很难阅读,也不可能在上面搜索。谢谢。我将编辑并添加它。这很有效!我刚刚添加了一个try
块,其中包含wait
调用。然后我在返回之前从一个catch
块抛出错误。我认为这是必要的,因为我需要抛出那个错误来停止函数,并在那个时候将错误发送给客户端。最后返回的url仅用于测试目的。非常感谢。@cbdev420-太好了!很高兴这有帮助,我还没有做过Firebase,但医生说你可以回报一个承诺,所以。。。如果要停止函数并在此时将错误发送给客户端,则不需要捕获并重新显示错误。如果要抛出与已抛出的错误不同的错误,只需捕获并重新抛出它。快乐编码!你是对的!即使没有catch
块,Firebase也会向我的客户端抛出(错误代码=内部)。尽管在我的函数日志中,它抱怨发生了未处理的错误
。所以我最好还是处理好它。由于我们在讨论这个问题,我一直在考虑以“总是成功”的方式处理函数中的错误,即:捕获错误但不抛出异常,我将成功返回错误对象,而不是常规响应,并在客户端检查。客户端总是进入。然后()
。您认为这两种方法都有(dis)优点吗?我会仔细检查结果,如果Firebase将错误返回到您的应用程序,那么它不是未经处理的,并且不应该存在未经处理的拒绝错误。你总是能成功:我不喜欢这样做,在我看来,成功和失败的道路是分开的。我会听从你的建议。非常感谢你的帮助!
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
};
});