请帮我弄清楚下面的 onCall 和 onRequest google 函数在返回行为上的区别。
onCall,问题是:除了第一次返回(如下所述)之外,所有返回都返回 null。 db 条目和其余代码工作正常。只是没有退货问题。
onRequest,每次返回都完美无缺。 db 条目和其余代码也可以正常工作。
您将看到的两者比较相同,但我似乎根本无法使其正常工作。任何关于如何让我的回报为 onCall 工作(并更好地构建它)的建议将不胜感激。
我热衷于坚持异步等待(而不是承诺)。使用 Node.js 12。我在 Flutter 中调用 onCall,不知道这是否与问题相关。
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");
}
});
答案 0 :(得分:1)
在查看您的代码时需要注意以下几点:
async/await
循环中使用 forEach
。问题是没有等待传递给 forEach()
的回调,请参阅更多解释 here 或 here。 但是,在您的情况下,您不需要遍历 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";
}
});