在 express 中使用异步

Using async in express

下面是我的休息 API 端点/注册。我现在遇到的问题是端点在 validateEmail 之后不会停止。即使在电子邮件 form-validation 失败并且 res.send() 完成后,端点仍会继续。所以我一直收到错误“错误:发送后无法设置 headers”。我希望能够在其函数(如 validateEmail、checkEmailInUse、makeUser 等)中完成端点。

router.post("/signup", async (req, res, next) => {
  const { email, password } = req.body;
  const users = req.app.get("users");
  validateEmail(res, email);
  await checkEmailInUse(res, users, email);
  const user = await makeUser(res, users, email, password);
  res.send({ message: "POST signup request OK", user });
});

function validateEmail(res, email) {
  const isEmail = emailFilter.test(email);
  if (!isEmail) {
    res.status(400).send({
      error: {
        message: "Requested email is not email type",
        type: "FormatValidation",
        location: "validateEmail"
      }
    });
    return;
  }
}

async function checkEmailInUse(res, users, email) {
  const query = { email };
  try {
    const user = await users.findOne(query);
    if (user) {
      res.send({ message: "The email is already used" });
    }
  } catch (err) {
    res.status(400).send({
      error: {
        message: "Failed to find user",
        type: "DatabaseError",
        location: "checkEmailInUse"
      }
    });
    return;
  }
}

代码在验证失败后继续运行,因为您调用了:

validateEmail(res, email);

然后您的代码就会继续运行。这是 Javascript 中的正常控制流程。您的函数会一直执行代码行,直到您在函数中 return 为止。 checkEmailInUse() 也是同样的问题。如果您有时想在这些函数内部发送响应并完成,那么您需要这些函数的 return 值,您可以检查该值,然后使用 if 语句来确定您的代码是否应该做更多或不是。

按照您在验证函数中发送错误响应的方式(这不是我可能构造事物的方式),您可以从这些函数中 return 值并测试这些 return 值像这样的请求处理程序:

router.post("/signup", async (req, res, next) => {
    const { email, password } = req.body;
    const users = req.app.get("users");
    if (validateEmail(res, email)) {
        if (await checkEmailInUse(res, users, email)) {
            const user = await makeUser(res, users, email, password);
            res.send({ message: "POST signup request OK", user });
        }
    }
  });

  function validateEmail(res, email) {
    const isEmail = emailFilter.test(email);
    if (!isEmail) {
      res.status(400).send({
        error: {
          message: "Requested email is not email type",
          type: "FormatValidation",
          location: "validateEmail"
        }
      });
      return false;
    }
    return true;
  }

  async function checkEmailInUse(res, users, email) {
    const query = { email };
    try {
      const user = await users.findOne(query);
      if (user) {
        res.send({ message: "The email is already used" });
        return false;
      } else {
        return true;  
      }
    } catch (err) {
      res.status(400).send({
        error: {
          message: "Failed to find user",
          type: "DatabaseError",
          location: "checkEmailInUse"
        }
      });
      return false;
    }
  }
}

但是,我想您可能会发现,如果您摆脱本地函数,这会更简单,因为这样当您发送响应时,您可以直接从主函数 return 完成。这是它的样子:

router.post("/signup", async (req, res, next) => {

    function err(res, message, type, location) {
        res.status(400).send({error: {message, type, location}});
    }

    const { email, password } = req.body;
    if (!emailFilter.test(email)) {
        err(res, "Requested email is not email type", "FormatValidation", "validateEmail");
        return;
    }
    const users = req.app.get("users");
    try {
        const user = await users.findOne({email});
        if (user) {
            res.send({ message: "The email is already used" });
            return;
        }
    } catch(e) {
        err(res, "Failed to find user", "DatabaseError", "checkEmailInUse");
        return;
    }
    try {
        const user = await makeUser(res, users, email, password);
        res.send({ message: "POST signup request OK", user });
    } catch(e) {
        err(res, "Failed to make user", "DatabaseError", "makeUser");
    }
}