Firebase Cloud Functions 正确的返回方式

问题描述 投票:0回答:1

我正在为 Firebase 编写一个云函数,它应该更改我的网络应用程序上的用户密码。一切工作正常,但我只是想知道我的代码是否经过优化且编写良好,因为糟糕的编码可能会导致 Firebase 本身产生意外的成本。 这是我的功能:

export const setNewPassword = v2.https
  .onRequest({cors: true}, async (request, response) => {
    // Se non è una richiesta POST
    if (request.method != "POST") {
      console.log("Wrong request method");
      response.status(400).send({code: "bad-request", message: "POST-required"});
      return;
    }

    // Recupero il body e lo convalido
    const body = request.body;
    if (!body) {
      console.log("Missing body");
      response.status(400).send({code: "bad-request", message: "missing-body"});
      return;
    }

    // Decifro il messaggio
    const message = CryptoJS.AES.decrypt(body, "key");
    const decryptedData = JSON.parse(message.toString(CryptoJS.enc.Utf8));
    // Ottengo i dati
    const newPassWord = decryptedData.newPass;
    const resetCode = decryptedData.resetCode;

    // Validazione dei dati
    if (newPassWord.length < 8) {
      response.status(500).send({code: "invalid-password", message: "too-short"});
      return;
    } else if (resetCode.length != 16) {
      response.status(500).send({code: "invalid-code", message: "code-length"});
      return;
    } else {
      // Recupero il documento firestore con il codice di reset associato alla mail
      const resetDoc = await firestore.collection("password-reset")
        .where("resetCode", "==", resetCode)
        .get();

      // Validazione del documento
      // Se esiste più di un documento
      if (!resetDoc) {
        console.log(`Code '${resetCode}' not found`);
        response.status(500).send({code: "invalid-code", message: "user-not-found"});
        return;
      }

      // Se il codice è duplicato
      if (resetDoc.docs.length > 1) {
        console.log(`Code '${resetCode}' is duplicated`);
        response.status(500).send({code: "invalid-code", message: "ambiguos-code"});
        return;
      }

      // Nel caso restante esiste solo un documento
      // Recupero la mail dell'utente
      const userMail = resetDoc.docs[0].data().email;
      // Recupero l'oggetto utente
      const user = await admin.auth().getUserByEmail(userMail);
      // Aggiorno la password
      admin.auth().updateUser(user.uid, {password: newPassWord})
        .then(() => {
          // Elimino il documento con il resetCode
          resetDoc.forEach((doc) => {
            doc.ref.delete();
          });
          console.log(`User '${userMail}' updated his password`);
          response.status(200).send({result: "password-updated"});
        })
        .catch((error) => {
          console.log(`Error '${error}' while updating password for user '${userMail}'`);
          response.status(500).send({error: error});
        });
    }
  });

我首先关心的是代码的每个检查点是否正确返回。我打算让 HTTPS 函数以

res.send()
终止,但我注意到,如果我只是在其后没有
return
的情况下放置它,我会收到错误“错误 [ERR_HTTP_HEADERS_SENT]:在将标头发送到客户端后无法设置标头” 那么,我这样做正确吗?

typescript firebase google-cloud-functions
1个回答
0
投票

我已经调整了你的代码。主要问题是您对异步 delete() 方法

并行
执行了未确定数量的调用,而没有正确等待所有这些执行完成。您可以使用
Promise.all()
,如下面的代码(或写入批处理)所示。

我删除了多余的

return;
不必要的行。

我还在

await
中使用了
await admin.auth().updateUser()
而不是
then()
。这些变化用
// <== Change here

标识
export const setNewPassword = v2.https.onRequest(
  { cors: true },
  async (request, response) => {
    try {
      // Se non è una richiesta POST
      if (request.method != "POST") {
        console.log("Wrong request method");
        response
          .status(400)
          .send({ code: "bad-request", message: "POST-required" });
      }

      // Recupero il body e lo convalido
      const body = request.body;
      if (!body) {
        console.log("Missing body");
        response
          .status(400)
          .send({ code: "bad-request", message: "missing-body" });
      }

      // Decifro il messaggio
      const message = CryptoJS.AES.decrypt(body, "key");
      const decryptedData = JSON.parse(message.toString(CryptoJS.enc.Utf8));
      // Ottengo i dati
      const newPassWord = decryptedData.newPass;
      const resetCode = decryptedData.resetCode;

      // Validazione dei dati
      if (newPassWord.length < 8) {
        response
          .status(500)
          .send({ code: "invalid-password", message: "too-short" });
      } else if (resetCode.length != 16) {
        response
          .status(500)
          .send({ code: "invalid-code", message: "code-length" });
      } else {
        // Recupero il documento firestore con il codice di reset associato alla mail
        const resetDoc = await firestore
          .collection("password-reset")
          .where("resetCode", "==", resetCode)
          .get();

        // Validazione del documento
        // Se esiste più di un documento
        if (resetDoc.empty) {.   // <== Change here
          console.log(`Code '${resetCode}' not found`);
          response
            .status(500)
            .send({ code: "invalid-code", message: "user-not-found" });
        }

        // Se il codice è duplicato
        if (resetDoc.docs.length > 1) {
          console.log(`Code '${resetCode}' is duplicated`);
          response
            .status(500)
            .send({ code: "invalid-code", message: "ambiguos-code" });
        }

        // Nel caso restante esiste solo un documento
        // Recupero la mail dell'utente
        const userMail = resetDoc.docs[0].data().email;
        // Recupero l'oggetto utente
        const user = await admin.auth().getUserByEmail(userMail);
        // Aggiorno la password
        await admin.auth().updateUser(user.uid, { password: newPassWord }); // <== Change here

        const promises = []; // <== Change here

        resetDoc.forEach((doc) => {
          promises.push(doc.ref.delete()); // <== Change here
        });

        await Promise.all(promises); // <== Change here

        console.log(`User '${userMail}' updated his password`);
        response.status(200).send({ result: "password-updated" });
      }
    } catch (error) {
      console.log(
        `Error '${error}' while updating password for user '${userMail}'`
      );
      response.status(500).send({ error: error });
    }
  }
);
© www.soinside.com 2019 - 2024. All rights reserved.