简体   繁体   English

如何修复Express中的“错误:发送标头后无法设置标头”

[英]How to fix “Error: Can't set headers after they are sent” in Express

I have recently been developing a MERN application and I have recently came into the trouble that express is saying that I am setting headers after they are sent. 我最近正在开发MERN应用程序,最近遇到了麻烦,快递表示我要在发送头之后设置头。

I am using mongo db and trying to update a user profile. 我正在使用mongo db并尝试更新用户配置文件。

I have tried to comment out my res.send points to find the issue but I have failed to do so. 我试图注释掉我的res.send发送点以找到问题,但我没有这样做。

Here is my post method for updating the user profile: 这是我更新用户个人资料的发布方法:

app.post("/api/account/update", (req, res) => {
    const { body } = req;
    // Validating and Checking Email
    if (body.email) {
      var email = body.email;
      email = email.toLowerCase();
      email = email.trim();
      body.email = email;
      User.find(
        {
          email: body.email
        },
        (err, previousUsers) => {
          if (previousUsers.length > 0) {
            return res.send({
              success: false,
              message:
                "Error: There is already another account with that email address"
            });
          } else {
          }
        }
      );
    }
    // Validating Names Function
    function checkName(name) {
      var alphaExp = /^[a-zA-Z]+$/;
      if (!name.match(alphaExp)) {
        return res.send({
          success: false,
          message: "Error: Names cannot contain special characters or numbers"
        });
      }
    }
    checkName(body.firstName);
    checkName(body.lastName);

    // Making sure that all fields cannot be empty
    if (!body.email && !body.firstName && !body.lastName) {
      return res.send({
        success: false,
        message: "Error: You cannot submit nothing"
      });
    }
    // Getting User ID from the current session
    UserSession.findById(body.tokenID, function(err, userData) {
      // Finding User ID using the current users session token
      if (userData.isDeleted) {
        return res.send({
          success: false,
          message:
            "Error: Session token is no longer valid, please login to recieve a new one"
        });
      }
      // Deleting the token ID from the body object as user table entry doesnt store tokens
      delete body.tokenID;
      // Finding the user profile and updating fields that are present
      User.findByIdAndUpdate(userData.userId, body, function(err, userInfo) {
        if (!err) {
          return res.send({
            success: true,
            message: "Success: User was updated successfully"
          });
        }
      });
    });
  });

This is the call that I am doing to the backend of the site: 这是我对网站后端的呼叫:

onUpdateProfile: function(fieldsObj) {
    return new Promise(function(resolve, reject) {
      // Get Session Token
      const obj = getFromStorage("the_main_app");
      // Defining what fields are getting updated
      fieldsObj.tokenID = obj.token;
      // Post request to backend
      fetch("/api/account/update", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(fieldsObj)
      })
        .then(res => {
          console.log("Verify Token - Res");
          return res.json();
        })
        .then(json => {
          console.log("Verify Token JSON", json);
          if (json.success) {
            window.location.href = `/manage-account?success=${json.success}`;
          } else {
            window.location.href = `/manage-account?success=${json.success}`;
          }
        });
    });
  }

Here is my error message that I am getting: 这是我收到的错误消息:

Error: Can't set headers after they are sent.
    at validateHeader (_http_outgoing.js:491:11)
    at ServerResponse.setHeader (_http_outgoing.js:498:3)
    at ServerResponse.header (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:767:10)
    at ServerResponse.send (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:170:12)
    at ServerResponse.json (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:267:15)
    at ServerResponse.send (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\express\lib\response.js:158:21)
    at C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\routes\api\account.js:270:22
    at C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\mongoose\lib\model.js:4641:16
    at process.nextTick (C:\Users\kieran.corkin\Desktop\Projects\Mern Template Final\mern-cra-and-server\server\node_modules\mongoose\lib\query.js:2624:28)
    at _combinedTickCallback (internal/process/next_tick.js:131:7)
    at process._tickCallback (internal/process/next_tick.js:180:9)
[nodemon] app crashed - waiting for file changes before starting...

Can anyone help me with this? 谁能帮我这个?

EDIT 编辑

I have changed my code, this seems to now work however I feel like its a little messy when put together. 我已经更改了代码,现在似乎可以了,但是放在一起时感觉有点混乱。 Any refactoring tips? 有重构提示吗?

Code: 码:

app.post("/api/account/update", (req, res) => {
    // Preform checks on data that is passed through
    const { body } = req;
    var messages = {
      ExistedUser:
        "Error: There is already another account with that email address",
      NameFormat: "Error: Names cannot contain special characters or numbers",
      BlankInputs: "Error: You cannot submit nothing",
      accountLoggedOut:
        "Error: Session token is no longer valid, please login to recieve a new one",
      successfullyUpdated: "Success: User was updated successfully"
    };
    var usersFound;
    if (body.email) {
      var email = body.email;
      email = email.toLowerCase();
      email = email.trim();
      body.email = email;
      User.find(
        {
          email: body.email
        },
        (err, UserCount) => {
          usersFound = UserCount;
        }
      );
    }
    function capitalize(text) {
      return text.replace(/\b\w/g, function(m) {
        return m.toUpperCase();
      });
    }
    if (body.firstName) {
      body.firstName = capitalize(body.firstName);
    }
    if (body.lastName) {
      body.lastName = capitalize(body.lastName);
    }

    //Making sure that all fields cannot be empty
    if (!body.email && !body.firstName && !body.lastName) {
      return res.send({
        success: false,
        message: messages.BlankInputs
      });
    }
    // Getting User ID from the current session
    UserSession.findById(body.tokenID, function(err, userData) {
      // Finding User ID using the current users session token
      if (userData.isDeleted) {
        return res.end({
          success: false,
          message: messages.accountLoggedOut
        });
      }
      if (userData) {
        // Deleting the token ID from the body object as user table entry doesnt store tokens
        delete body.tokenID;
        // Finding the user profile and updating fields that are present
        User.findByIdAndUpdate(userData.userId, body, function(err, userInfo) {
          if (userInfo) {
            if (!usersFound.length > 0) {
              return res.send({
                success: true,
                message: messages.successfullyUpdated
              });
            } else {
              return res.send({
                success: false,
                message: messages.ExistedUser
              });
            }
          }
        });
      }
    });
  });

You're calling res.send() twice. 您两次调用res.send() res.send() ends the process. res.send()结束该过程。 You ought to refactor such that you call res.write() and only call res.send() when you're done. 您应该进行重构,以便在完成后调用res.write()并仅调用res.send()

This StackOverflow link describes the difference in more detail. 该StackOverflow链接更详细地描述了差异。 What is the difference between res.send and res.write in express? express中的res.send和res.write有什么区别?

I believe this is happening, as you're trying to send a response after the first / initial response has already been sent to the browser. 我相信这种情况正在发生,因为您正在尝试在第一个/初始响应已发送到浏览器之后发送响应。 For example: 例如:

checkName(body.firstName);
checkName(body.lastName);

Running this function twice is going to try and yield 2 different "response" messages. 两次运行此功能将尝试产生2个不同的“响应”消息。

The product of a single route, should ultimately be a single response. 单一途径的产物最终应该是单一反应。

Thanks for all your help on this issue. 感谢您在此问题上的所有帮助。

Here is my final code that allowed it to work. 这是我允许其工作的最终代码。

I have also tried to "refactor" it too. 我也尝试过“重构”它。 Let me know if you'd do something else. 让我知道您是否还要做其他事情。

app.post("/api/account/update", (req, res) => {
    const { body } = req;
    console.log(body, "Logged body");
    // Defining objects to be used at the end of request
    var updateUserInfo = {
      userInfo: {},
      sessionToken: body.tokenID
    };
    var hasErrors = {
      errors: {}
    };

    // Checking that there is at least one value to update
    if (!body.email && !body.firstName && !body.lastName) {
      var blankError = {
        success: false,
        message: "Error: You cannot change your details to nothing"
      };
      hasErrors.errors = { ...hasErrors.errors, ...blankError };
    } else {
      console.log("Normal Body", body);
      clean(body);
      console.log("Cleaned Body", body);
      updateUserInfo.userInfo = body;
      delete updateUserInfo.userInfo.tokenID;
    }
    // Function to check if object is empty
    function isEmpty(obj) {
      if (Object.keys(obj).length === 0) {
        return true;
      } else {
        return false;
      }
    }

    // Function to remove objects from body if blank
    function clean(obj) {
      for (var propName in obj) {
        if (obj[propName] === "" || obj[propName] === null) {
          delete obj[propName];
        }
      }
    }

    // Checking and Formatting Names Given
    function capitalize(text) {
      return text.replace(/\b\w/g, function(m) {
        return m.toUpperCase();
      });
    }
    if (body.firstName) {
      body.firstName = capitalize(body.firstName);
    }
    if (body.lastName) {
      body.lastName = capitalize(body.lastName);
    }

    // Checking and formatting email
    if (body.email) {
      body.email = body.email.toLowerCase();
      body.email = body.email.trim();

      // Checking for email in database
      User.find({ email: body.email }, (err, EmailsFound) => {
        if (EmailsFound.length > 0) {
          var EmailsFoundErr = {
            success: false,
            message: "There is already an account with that email address"
          };
          hasErrors.errors = { ...hasErrors.errors, ...EmailsFoundErr };
        }
      });
    }
    // Getting User Session Token
    UserSession.findById(updateUserInfo.sessionToken, function(err, userData) {
      // Finding User ID using the current users session token
      if (userData.isDeleted) {
        var userDeletedError = {
          success: false,
          message:
            "Your account is currently logged out, you must login to change account details"
        };
        hasErrors.errors = { ...hasErrors.errors, ...userDeletedError };
      } else {
        // Finding the user profile and updating fields that are present
        User.findByIdAndUpdate(
          userData.userId,
          updateUserInfo.userInfo,
          function(err, userInfo) {
            // userInfo varable contains user db entry
            if (err) {
              var updateUserError = {
                success: false,
                message: "Error: Server Error"
              };
              hasErrors.errors = {
                ...hasErrors.errors,
                ...updateUserError
              };
            }
            if (isEmpty(hasErrors.errors)) {
              res.send({
                success: true,
                message: "Success: You have updated your profile!"
              });
            } else {
              res.send({
                success: false,
                message: hasErrors.errors
              });
            }
          }
        );
      }
    });
  });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM