Cannot set headers after they are sent to the client

huangapple go评论69阅读模式
英文:

Cannot set headers after they are sent to the client

问题

Here is the translated code portion:

我的代码中出现了错误。我尝试使用jsonwebtoken生成令牌,但最终出现了错误“Cannot set headers after they are sent to the client”。
以下是详细的错误日志:

```none
throw er; // 未处理的 'error' 事件
      ^

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at new NodeError (node:internal/errors:393:5)
    at ServerResponse.setHeader (node:_http_outgoing:644:11)
    at ServerResponse.header (D:\web dev\projects\Mern-Project\server\node_modules\express\lib\response.js:794:10)
    at ServerResponse.send (D:\web dev\projects\Mern-Project\server\node_modules\express\lib\response.js:174:12)
    at ServerResponse.json (D:\web dev\projects\Mern-Project\server\node_modules\express\lib\response.js:278:15)
    at D:\web dev\projects\Mern-Project\server\router\auth.js:45:34
    at D:\web dev\projects\Mern-Project\server\node_modules\mongoose\lib\model.js:5228:18
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11)
Emitted 'error' event on Function instance at:
    at D:\web dev\projects\Mern-Project\server\node_modules\mongoose\lib\model.js:5230:15
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11) {
  code: 'ERR_HTTP_HEADERS_SENT'
}

我尝试在注册和登录网站时使用jsonwebtoken包生成用户令牌。
以下是auth文件的代码,其中创建了登录和注册方法:

const express = require("express");
const { default: mongoose } = require("mongoose");
const router = express.Router();
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
require("../db/conn");
const User = require("../model/userSchema");
router.get("/", (req, res)=>{
    res.send("Hello world to server router js");
});

router.post("/register", (req, res)=>{
  bcrypt.hash(req.body.password, 12, function (err, hash) { 
    const newUser = new User({
      name:req.body.name,
      email: req.body.email,
      phone: req.body.phone,
      work: req.body.work,
      password: hash
      
    });
    // 创建令牌
    const email = req.body.email;
    const token = jwt.sign(
      { user_id: newUser._id, email },
      process.env.TOKEN_KEY,
      {
        expiresIn: "2h",
      }
    );
    // 保存用户令牌
    newUser.token = token;
    res.status(201).json(newUser);

    if(!newUser.name || !newUser.email || !newUser.phone || !newUser.work || !newUser.password){
      return res.status(422).json({error: "请填写必填字段"});
    }
    User.findOne({email: newUser.email}, function (err, userExist) { 
      if(err){
        console.log(err);
        res.status(500).json({error: "注册失败"});
      }else{
        if(userExist){
          return res.status(422).json({error: "电子邮件已存在"});
        }else{
          newUser.save();
          res.status(201).json({message: "用户成功注册"});
        }
      }
     });

   });
  });

  // 登录路由
  router.post("/signin", (req, res)=>{
    if(!req.body.email || !req.body.password){
      return res.status(400).json({error: "请填写必要的数据"});
   }else{
    bcrypt.hash(req.body.password, 12, function (err, hash) { 
      User.findOne({email: req.body.email}, function (err, foundUser) {
        if(err){
          console.log(err);
        }else{
          if(foundUser){
            bcrypt.compare(req.body.password, foundUser.password, function (err, result) {
                  if(result){
                    res.json({message: "登录成功"})
                  }else{
                    res.json({message: "密码错误"});
                  }
              });
              const email = req.body.email;
              const token = jwt.sign(
                { user_id: foundUser._id, email },
                process.env.TOKEN_KEY,
                {
                  expiresIn: "2h",
                }
              );
              foundUser.token = token;
              res.status(200).json(foundUser);
          }else{
            res.status(400).json({message: "用户未找到"});
          };
        }
      })
    })
  }
  });

module.exports = router;

这是数据库模式和模型的代码:

const mongoose = require("mongoose");

const userSchema = new mongoose.Schema({
    name:{
        type:String,
        required:true
    },
    email:{
        type:String,
        required:true
    },
    phone:{
        type:Number,
        required:true
    },
    work:{
        type:String,
        required:true
    },
    password:{
        type:String,
        required:true
    },
    tokens:[
         { token:{
            type:String,
            required:true
         }

    }]

});

const User = mongoose.model("User", userSchema);

module.exports = User;

请注意,我只提供了代码的翻译,没有回答与翻译无关的问题。

英文:

What is error in my code? I had tried to generate tokens using jsonwebtoken but ended up having a error "Cannot set headers after they are sent to the client".
This is detailed log of error:

throw er; // Unhandled 'error' event
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:393:5)
at ServerResponse.setHeader (node:_http_outgoing:644:11)
at ServerResponse.header (D:\web dev\projects\Mern-Project\server\node_modules\express\lib\response.js:794:10)
at ServerResponse.send (D:\web dev\projects\Mern-Project\server\node_modules\express\lib\response.js:174:12)
at ServerResponse.json (D:\web dev\projects\Mern-Project\server\node_modules\express\lib\response.js:278:15)
at D:\web dev\projects\Mern-Project\server\router\auth.js:45:34
at D:\web dev\projects\Mern-Project\server\node_modules\mongoose\lib\model.js:5228:18
at process.processTicksAndRejections (node:internal/process/task_queues:77:11)
Emitted 'error' event on Function instance at:
at D:\web dev\projects\Mern-Project\server\node_modules\mongoose\lib\model.js:5230:15
at process.processTicksAndRejections (node:internal/process/task_queues:77:11) {
code: 'ERR_HTTP_HEADERS_SENT'
}

I tried to generate the token for user while registering and sign- in website by using jsonwebtoken package.
Here is code of auth file where is created login and sign-in methods

const express = require("express");
const { default: mongoose } = require("mongoose");
const router = express.Router();
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
require("../db/conn");
const User = require("../model/userSchema");
router.get("/", (req, res)=>{
    res.send("Hello world to server router js");

});

router.post("/register", (req, res)=>{
  bcrypt.hash(req.body.password, 12, function (err, hash) { 
    const newUser = new User({
      name:req.body.name,
      email: req.body.email,
      phone: req.body.phone,
      work: req.body.work,
      password: hash
      
    });
    // Create token
    const email = req.body.email;
    const token = jwt.sign(
      { user_id: newUser._id, email },
      process.env.TOKEN_KEY,
      {
        expiresIn: "2h",
      }
    );
    // save user token
    newUser.token = token;
    res.status(201).json(newUser);

    if(!newUser.name || !newUser.email || !newUser.phone || ! newUser.work || !newUser.password){
      return res.status(422).json({error: "Plz fill the required field"});
    }
    User.findOne({email: newUser.email}, function (err, userExist) { 
      if(err){
        console.log(err);
        res.status(500).json({error: "failed to register"});
      }else{
        if(userExist){
          return res.status(422).json({error: "Email already Exist"});
        }else{
          newUser.save();
          res.status(201).json({message: "user registered succesfully"});
        }
      }
     });

   });
  });

  //LOgin route
  router.post("/signin", (req, res)=>{
    if(!req.body.email || !req.body.password){
      return res.status(400).json({error: "Plz fill the required data"});
   }else{
    bcrypt.hash(req.body.password, 12, function (err, hash) { 
      User.findOne({email: req.body.email}, function (err, foundUser) {
        if(err){
          console.log(err);
        }else{
          if(foundUser){
            bcrypt.compare(req.body.password, foundUser.password, function (err, result) {
                  if(result){
                    res.json({message: "successfully log in"})
                  }else{
                    res.json({message: "incorrect password"});
                  }
              });
              const email = req.body.email;
              const token = jwt.sign(
                { user_id: foundUser._id, email },
                process.env.TOKEN_KEY,
                {
                  expiresIn: "2h",
                }
              );
              foundUser.token = token;
              res.status(200).json(foundUser);
          }else{
            res.status(400).json({message: "user not found"});
          };
        }
      })
    })
  }
  });

module.exports = router;

This is code to database schema and model:

const mongoose = require("mongoose");

const userSchema = new mongoose.Schema({
    name:{
        type:String,
        required:true
    },
    email:{
        type:String,
        required:true
    },
    phone:{
        type:Number,
        required:true
    },
    work:{
        type:String,
        required:true
    },
    password:{
        type:String,
        required:true
    },
    tokens:[
         { token:{
            type:String,
            required:true
         }

    }]

});

const User = mongoose.model("User", userSchema);

module.exports = User;

答案1

得分: 2

请注意,无论何时发送响应,都不代表执行结束,HTTP每个请求只有一个响应。因此,为了停止函数的执行,您总是需要使用return

您的代码中有一些问题:

newUser.token = token;
res.status(201).json(newUser);

在这里,您必须决定是发送给客户端还是继续检查数据库。

因为几行后,您有以下条件,可能会发送给客户端另一个响应:

if (!newUser.name || !newUser.email || !newUser.phone || !newUser.work || !newUser.password) {
  return res.status(422).json({ error: "请填写必填字段" });
}

在您的signin路由中发生了相同的问题:

bcrypt.compare(req.body.password, foundUser.password, function (err, result) {
  if (result) {
    res.json({ message: "成功登录" })
  } else {
    res.json({ message: "密码不正确" });
  }
});
...
res.status(200).json(foundUser);
英文:

Please pay attention whenever you send a response, it doesn't mean that the execution ends, and also the HTTP has just only one response per request. Hence, to stop the execution of a function you always need to put return.

There are some parts in your code, which makes trouble:

newUser.token = token;
res.status(201).json(newUser);

Here you must decide whether to send the client or continue checking the database.

Because a few lines after, you have this condition, which might send the client another response:

if(!newUser.name || !newUser.email || !newUser.phone || ! newUser.work || !newUser.password){
  return res.status(422).json({error: "Plz fill the required field"});
}

The same issue happened in your signin route:

bcrypt.compare(req.body.password, foundUser.password, function (err, result) {
  if(result){
    res.json({message: "successfully log in"})
  }else{
    res.json({message: "incorrect password"});
  }
});
...
res.status(200).json(foundUser);

huangapple
  • 本文由 发表于 2023年1月4日 03:36:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/74997926.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定