请帮我弄清楚下面onCall和onRequest谷歌函数在返回行为上的区别。
-
onCall,问题是:除了第一次返回外,所有返回都返回null(如下所述(。数据库条目和其余代码运行良好。只是没有退货问题。
-
onRequest,每次返回都非常好。数据库条目和其余代码也可以正常工作。
正如你将看到的,两者比较相同,但我似乎根本无法让它发挥作用。任何关于如何让我的回报为onCall工作(并更好地构建它(的建议都将不胜感激。
我热衷于坚持异步等待(而不是承诺(。使用Node.js 12。我打电话给Flutter的onCall,不知道这是否与这个问题有关。
随叫随到:
exports.applyUserDiscount = functions.https.onCall(async (data, context) => {
if (!context.auth) return {message: "Authentication Required!", code: 401};
const uid = context.auth.uid;
const discountCode = data["discountCode"];
const cartTotal = data["cartTotal"];
try {
return await db.collection("discountCodes").where("itemID", "==", discountCode).limit(1).get()
.then(async (snapshot) => {
if (snapshot.empty) {
return "doesNotExist"; // The only return that works.
} else { // Everything else from here onwards returns null.
snapshot.forEach(async (doc) => {
if (doc.data().redeemed == true) {
return "codeUsed";
} else {
const newCartTotal = cartTotal - doc.data().discountAmount;
if (newCartTotal < 0) {
return "lessThanTotal";
} else {
doc.ref.update({
redeemed: true,
uid: uid,
redeemDate: fireDateTimeNow,
});
await db.collection("userdata").doc(uid).set({
cartDiscount: admin.firestore.FieldValue.increment(-doc.data().discountAmount),
}, {merge: true});
return doc.data().discountAmount.toString();
}
}
});
}
});
} catch (error) {
console.log("Error:" + error);
return "error";
}
});
onRequest:
exports.applyUserDiscount = functions.https.onRequest(async (req, res) => {
const uid = req.body.uid;
const discountCode = req.body.discountCode;
const cartTotal = req.body.cartTotal;
try {
return await db.collection("discountCodes").where("itemID", "==", discountCode).limit(1).get()
.then(async (snapshot) => {
if (snapshot.isempty) {
res.send("doesNotExist");
} else {
snapshot.forEach(async (doc) => {
if (doc.data().redeemed == true) {
res.send("codeUsed");
} else {
const newCartTotal = cartTotal - doc.data().discountAmount;
if (newCartTotal < 0) {
res.send("lessThanTotal");
} else {
doc.ref.update({
redeemed: true,
uid: uid,
redeemDate: fireDateTimeNow,
});
await db.collection("userdata").doc(uid).set({
cartDiscount: admin.firestore.FieldValue.increment(-doc.data().discountAmount),
}, {merge: true});
res.send(doc.data().discountAmount.toString());
}
}
});
}
});
} catch (error) {
console.log(error);
res.send("error");
}
});
查看代码时需要注意以下几点:
- 不应在
forEach
循环中使用async/await
。问题是没有等待传递给forEach()
的回调,请参阅此处或此处的更多解释但是,在您的情况下,您不需要在QuerySnapshot
上循环,因为它只包含一个文档。您可以使用docs
属性,该属性返回QuerySnapshot
中所有文档的数组,并获取第一个(也是唯一的(元素 - 您将
then()
与async/await
混合使用,这是不推荐的 - 我建议对";错误";情况,如
doesNotExist
、codeUsed
或lessThanTotal
,但由您选择。例如,lessThanTotal
案例是一个错误或标准商业案例,这一事实值得商榷。。。因此,如果您更喜欢发送";文本";响应,我建议将此响应封装在具有一个属性的对象中:在前端,响应将始终具有相同的格式
因此,以下内容应该能起到作用。请注意,我使用response
元素发回对象,包括可能被视为错误的情况。如上所述,在这些情况下,您可以抛出一个异常。
exports.applyUserDiscount = functions.https.onCall(async (data, context) => {
if (!context.auth) ... //See https://firebase.google.com/docs/functions/callable#handle_errors
const uid = context.auth.uid;
const discountCode = data["discountCode"];
const cartTotal = data["cartTotal"];
try {
const snapshot = await db.collection("discountCodes").where("itemID", "==", discountCode).limit(1).get();
if (snapshot.empty) {
//See https://firebase.google.com/docs/functions/callable#handle_errors
} else {
const uniqueDoc = snapshot.docs[0];
if (uniqueDoc.data().redeemed == true) {
return { response: "codeUsed" };
} else {
const newCartTotal = cartTotal - uniqueDoc.data().discountAmount;
if (newCartTotal < 0) {
return { response: "lessThanTotal" };
} else {
await uniqueDoc.ref.update({ // See await here!!
redeemed: true,
uid: uid,
redeemDate: fireDateTimeNow,
});
await db.collection("userdata").doc(uid).set({
cartDiscount: admin.firestore.FieldValue.increment(-uniqueDoc.data().discountAmount),
}, { merge: true });
return {
response: uniqueDoc.data().discountAmount.toString()
}
}
}
}
} catch (error) {
console.log("Error:" + error);
return "error";
}
});