未处理的拒绝错误:在JavaScript中发送标头后无法设置标头

时间:2019-01-31 22:55:22

标签: javascript node.js

我无法理解JavaScript中的异步性。我认为我的代码应在我评论过的地方停止(转到if处),但是会引发错误:

  

未处理的拒绝错误:发送标头后无法设置。

很抱歉获得如此大的代码,但我想发送所有信息以使情况非常清楚。

我认为我的方法setTransferHistory(...)sendAuthorizationKey(...)应该是异步/等待的,并且在完成此代码后,我想返回状态200。

Transaction.findOne({
                where: {
                  id_sender: senderId,
                  id_recipient: recipientId,
                  amount_money: amountMoney,
                  transfer_title: transferTitle,
                  authorization_key: authorizationKey,
                  authorization_status: setAuthorizationStatus(0),
                },
                order: [['date_time', 'DESC']],
              }).then(isAuthorizationKey => {
                if (!isAuthorizationKey) {
                  setTransferHistory(
                    senderId,
                    recipientId,
                    amountMoney,
                    transferTitle,
                    authorizationKey,
                  );
                  sendAuthorizationKey(
                    senderId,
                    recipientId,
                    amountMoney,
                    authorizationKey,
                  );
                  return res.status(200).json({ success: true }); /* it should stop in this place */
                }

所有控制器:

exports.register = (req, res) => {
  function getTodayDate() {
    const today = new Date();
    return today;
  }

  function setAuthorizationStatus(status) {
    const authorizationStatus = status;
    return authorizationStatus;
  }

  async function getSenderEmail(id) {
    try {
      const isUser = await User.findOne({
        where: {
          id,
        },
      });
      return isUser.email;
    } catch (e) {
      /* just ignore */
    }
  }

  async function getRecipientName(id) {
    try {
      const isUser = await User.findOne({
        where: {
          id,
        },
      });
      return `${isUser.name} ${isUser.surname}`;
    } catch (e) {
      /* just ignore */
    }
  }

  function setAuthorizationKey() {
    let authorizationKey = '';
    const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

    for (let i = 0; i < 5; i++)
      authorizationKey += possible.charAt(
        Math.floor(Math.random() * possible.length),
      );

    return authorizationKey;
  }

  async function sendAuthorizationKey(
    senderId,
    recipientId,
    amountMoney,
    authorizationKey,
  ) {
    await nodemailer.createTestAccount();
    const transporter = nodemailer.createTransport({
      host: env.nodemailer.host,
      port: env.nodemailer.port,
      secure: false,
      auth: {
        user: env.nodemailer.username,
        pass: env.nodemailer.password,
      },
    });

    const mailOptions = {
      from: "example"`,
      to: `${await getSenderEmail(senderId)}`,
      subject: 'example',
      text: 'example`,
    };

    await transporter.sendMail(mailOptions);
  }

  function setTransferHistory(
    senderId,
    recipientId,
    amountMoney,
    transferTitle,
    authorizationKey,
  ) {
    Transaction.create({
      id_sender: senderId,
      id_recipient: recipientId,
      date_time: getTodayDate(),
      amount_money: amountMoney,
      transfer_title: transferTitle,
      authorization_key: authorizationKey,
      authorization_status: setAuthorizationStatus(0),
    });
  }

  Bill.findOne({
    where: {
      account_bill: req.body.account_bill,
    },
  }).then(isAccountBill => {
    if (isAccountBill) {
      const recipientId = isAccountBill.id_owner;
      const authorizationKey = setAuthorizationKey();
      const senderId = req.body.id_sender;
      const amountMoney = req.body.amount_money;
      const transferTitle = req.body.transfer_title;

      if (recipientId !== senderId) {
        Bill.findOne({
          where: {
            id_owner: senderId,
          },
        }).then(isAvailableFunds => {
          if (isAvailableFunds) {
            const senderAvailableFunds = isAvailableFunds.available_funds;

            if (senderAvailableFunds >= amountMoney && amountMoney > 0) {
              Transaction.findOne({
                where: {
                  id_sender: senderId,
                  id_recipient: recipientId,
                  amount_money: amountMoney,
                  transfer_title: transferTitle,
                  authorization_key: authorizationKey,
                  authorization_status: setAuthorizationStatus(0),
                },
                order: [['date_time', 'DESC']],
              }).then(isAuthorizationKey => {
                if (!isAuthorizationKey) {
                  setTransferHistory(
                    senderId,
                    recipientId,
                    amountMoney,
                    transferTitle,
                    authorizationKey,
                  );
                  sendAuthorizationKey(
                    senderId,
                    recipientId,
                    amountMoney,
                    authorizationKey,
                  );
                  return res.status(200).json({ success: true }); /* it should stop in this place */
                }
                return res.status(400).json({
                  error: 'Authorization key has been sent',
                  success: false,
                });
              });
            }
            return res.status(400).json({
              error: 'Sender does not have enough money',
              success: false,
            });
          }
          return res
            .status(404)
            .json({ error: 'Id sender doesnt exist', success: false });
        });
      }
      return res
        .status(404)
        .json({ error: 'Attempt payment to myself', success: false });
    }
    return res
      .status(404)
      .json({ error: 'Recipient does not exist', success: false });
  });
};

1 个答案:

答案 0 :(得分:0)

在Promise回调中调用return也不会从调用代码中返回。这是简化示例中的代码

if (someCondition) {
  doSomethingAsync().then(() =>
    ...
    return res.status(200).json(...);
  });
}
return res.status(400).json(...);

现在给定doSomethingAsync是异步的,您正在传递一个回调函数(then),以便在I / O绑定过程完成时得到通知。但是,在进行此调用的同时,当前代码仍将运行完成,因此将非故意地调用return res.status(400).json(...),这意味着在为I / O绑定操作触发回调时,您已经结束了请求,因此收到适当的错误。

要解决此问题,您需要先等待异步代码完成,然后再继续执行 ,这正是async / await设计的目的

if (someCondition) {
  await doSomethingAsync();
  return res.status(200).json(...);
}
return res.status(400).json(...);

注意-您的代码中确实有一些场景,其中您调用async函数,但没有await函数,例如sendAuthorizationKey,不确定这是否是故意的,但确实意味着代码很可能在其余代码执行之前无法完成