【问题标题】:onRequest vs onCall returning nullonRequest 与 onCall 返回 null
【发布时间】:2021-04-21 19:07:57
【问题描述】:

请帮我弄清楚下面的 onCall 和 onRequest google 函数在返回行为上的区别。

  • onCall,问题:在所有返回中返回 null,除了第一次返回(如下所述)。 db 条目和其余代码工作正常。只是没有退货问题。

  • onRequest,每次返回都返回完美。 db 条目和其余代码也可以正常工作。

你会看到两者比较相同,但我似乎根本无法让它工作。任何关于如何让我的回报为 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");
  }
});

【问题讨论】:

    标签: javascript node.js firebase google-cloud-firestore google-cloud-functions


    【解决方案1】:

    查看代码时需要注意几点:

    • 您不应在forEach 循环中使用async/await。问题是没有等待传递给forEach() 的回调,请参阅herehere 的更多解释。 但是,在您的情况下,您不需要遍历QuerySnapshot 因为它只包含一个文档。您可以使用docs 属性返回QuerySnapshot 中所有文档的数组并获取第一个(也是唯一的)元素。
    • 您将then()async/await 混淆了,不建议这样做。
    • 对于“错误”情况,我建议throw exceptions,例如doesNotExistcodeUsedlessThanTotal,但您可以自行选择。例如,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";
        }
    });
    

    【讨论】:

    • 非常感谢您简洁的回答和建议,它现在完美运行。我把它们都变成了例外,除了折扣金额被退回时,效果很好!非常感谢??。
    猜你喜欢
    • 2022-09-26
    • 1970-01-01
    • 2021-08-15
    • 2018-12-06
    • 2019-11-16
    • 1970-01-01
    • 2019-02-01
    • 1970-01-01
    • 2020-12-01
    相关资源
    最近更新 更多