Node.js,Express:在将响应发送给客户端后无法设置标题

13 浏览
0 Comments

Node.js,Express:在将响应发送给客户端后无法设置标题

此问题已经有了答案:

错误:无法在发送给客户端之后设置标题

首先,我阅读了所有其他StackOverflow答案和GitHub问题,但它们似乎都没有解决我的问题。 下面是一些代码(其中一些已过时,对于脏代码很抱歉):

var express = require('express');
var fs = require('fs');
var path = require('path');
var parser = require('body-parser');
//Initializing the Express Framework
const app = express();
const mongoose = require('mongoose');
const uuidv4 = require ('uuid/v4');
var jose = require('node-jose');
var secureRandom = require('secure-random');
var bcrypt = require('bcrypt');
const jwt = require('express-jwt');
const jwt2 = require('jsonwebtoken');
var userSchema = new mongoose.Schema({
  username: {type:String,unique:true},
  password: String
},{timestamps:true})
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
var signingKey = secureRandom(256, {type: 'Buffer'});
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Add headers
app.use(function (req, res, next) {
  res.removeHeader('X-Powered-By');
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type,Authorization');
  res.setHeader('Access-Control-Allow-Credentials', true);
  next();
});
var claims = {
  iss: "http://example.com/",  // The URL of your service
  sub: "users/admin1",    // The UID of the user in your system
  name: "User Name",
  scope: "self, admins"
}
userSchema.pre('save', function (next) {
  var user = this;
  if (!user.isModified('password')) {return next()};
  bcrypt.hash(user.password,10).then((hashedPassword) => {
      user.password = hashedPassword;
      next();
  })
}, function (err) {
  next(err);
})
userSchema.methods.comparePassword=function(candidatePassword,next){    bcrypt.compare(candidatePassword,this.password,function(err,isMatch){
      if(err) return next(err);
      next(null,isMatch)
  })
}
module.exports = mongoose.model("user", userSchema);
function protectRoute(req,res,next){
  // if user exists the token was sent with the request
  if(req.user){
   //if user exists then go to next middleware
     next();
  }
// token was not sent with request send error to user
  else{
     res.status(500).json({error:'login is required'});
  }
}
/* app.get('/protected',
  jwt({secret: 'shhhhhhared-secret'}),
  function(req, res) {
    if (!req.user.admin) return res.sendStatus(401);
    res.sendStatus(200);
  }); */
MongoClient.connect(url,  {
  useUnifiedTopology: true,
  useNewUrlParser: true,
  },function(err, db) {
  if (err) throw err;
  var dbo = db.db("demo");
  dbo.collection("demo").find({}).toArray(function(err, result) {
    if (err) throw err;
    console.log(result);
    db.close();
  });
}); 
readJsonFile = function(fname, res) {
    fs.readFile(fname, 'utf8', function (err,data) {
        if (err) {
            console.log(err);
        }
        res.send(data.toString().replace(/\n|\r/g,''));
    });
}
app.get('/', function (req, res) {
  res.send('Hello World!');
});
app.get('/users', function (req, res) {
    MongoClient.connect(url,  {
    useUnifiedTopology: true,
    useNewUrlParser: true,
    },function(err, db) {
    if (err) throw err;
    var dbo = db.db("demo");
    dbo.collection("users").find({}).toArray(function(err, result) {
      if (err) throw err;
      res.send(result);
      db.close();
    });
  }); 
  console.log("GET UserCollection from MongoDB");
});
app.post('/users/:id', verifyToken, function (req, res){
  jwt2.verify(req.token, 'secretkey', (err, auth) =>{
    if(err){
      res.sendStatus(403);
    } else {
      res.json({
        message: 'User created (in theory)',
        authData
      })
    }
  })
  res.json({
    message: 'User created (in theory)2'
  })
});
app.post('/api/login', function (req, res){
  // Mock user TODO: implement proper BackEnd!
  const user = {
    id:1,
    username:'brad',
    email: 'brad@gmail.com'
  }
  jwt2.sign({user}, 'secretkey', { expiresIn: '1h'}, (err, token) =>{
    res.json({
      token
    });
  });
});
app.get('/user', function (req, res) {
    readJsonFile('user.json', res);
  console.log("GET User");
});
// FORMAT OF TOKEN
// Authorization: Bearer 
// Verify Token
function verifyToken(req, res, next){
  // Get auth header value
  const bearerHeader = req.headers['authorization'];
  // Check if bearer is undefined
  if(typeof bearerHeader !== 'undefined'){
    // Split at the space
    const bearer = bearerHeader.split(' ');
    // Get token from array
    const bearerToken = bearer[1];
    // Set the token
    req.token = bearerToken;
    // Next middleware
    next();
    res.json({message: "Login successful"});
  }
    else{
      // Forbidden
      res.sendStatus(403);
      next();
    }
  }
app.listen(3000, function () {
  console.log('Listening on port 3000!');
});
if(process.env.NODE_ENV !== 'production') {
  process.once('uncaughtException', function(err) {
    console.error('FATAL: Uncaught exception.');
    console.error(err.stack||err);
    setTimeout(function(){
      process.exit(1);
    }, 100);
  });
}

在我运行应用程序并POST URL /users/5之后,我会收到以下错误,然后应用程序崩溃:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:485:11)
    at Array.write (C:\Users\User\Documents\Project\Project2\node_modules\finalhandler\index.js:285:9)
    at listener (C:\Users\User\Documents\Project\Project2\node_modules\on-finished\index.js:169:15)
    at onFinish (C:\Users\User\Documents\Project\Project2\node_modules\on-finished\index.js:100:5)
    at callback (C:\Users\User\Documents\Project\Project2\node_modules\ee-first\index.js:55:10)
    at IncomingMessage.onevent (C:\Users\User\Documents\Project\Project2\node_modules\ee-first\index.js:93:5)
    at IncomingMessage.emit (events.js:215:7)
    at endReadableNT (_stream_readable.js:1183:12)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)
ReferenceError: authData is not defined
    at C:\Users\User\Documents\Project\Project2\src\app.js:134:9
    at C:\Users\User\Documents\Project\Project2\node_modules\jsonwebtoken\verify.js:223:12
    at getSecret (C:\Users\User\Documents\Project\Project2\node_modules\jsonwebtoken\verify.js:90:14)
    at Object.module.exports [as verify] (C:\Users\User\Documents\Project\Project2\node_modules\jsonwebtoken\verify.js:94:10)       
    at C:\Users\User\Documents\Project\Project2\src\app.js:127:8
    at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)    
    at next (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\route.js:137:13)
    at verifyToken (C:\Users\User\Documents\Project\Project2\src\app.js:178:5)
    at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)    
    at next (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)    
    at C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:281:22
    at param (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:354:14)
    at param (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:365:14)
    at Function.process_params (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:410:3)

我尝试添加了return和next语句,但都没有用。

P.S这有助于理解问题:

当你发送响应后,再试图发送响应时就会出现此错误。为此,您必须检查是否有任何代码片段在两次发送响应。有时候它发生在nodejs的异步行为中。有时,进程将处于事件循环中,我们会发送响应,当它执行完时,响应将再次发送。因此,您可以使用回调或异步等待等待执行。

PP.S

在遵循答案中给出的代码示例后,现在我收到了此错误(现在与链接的问题更相似):

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:485:11)
    at ServerResponse.header (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\response.js:771:10)
    at ServerResponse.send (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\response.js:170:12)
    at ServerResponse.json (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\response.js:267:15)
    at verifyToken (C:\Users\User\Documents\Project\Project2\src\app.js:176:9)
    at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)
    at C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:281:22 
    at param (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:354:14)
    at param (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:365:14)
    at Function.process_params (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:410:3)
    at next (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\index.js:275:10)
    at C:\Users\User\Documents\Project\Project2\src\app.js:35:3
    at Layer.handle [as handle_request] (C:\Users\User\Documents\Project\Project2\node_modules\express\lib\router\layer.js:95:5)

admin 更改状态以发布 2023年5月20日
0
0 Comments

在你的代码 app.post('/users/:id'..) 中,你发送了两次响应。因此,第二次会出现错误,因为响应已经发送。

还有另一个错误:authData 没有定义,因为应该是 auth

    app.post('/users/:id', verifyToken, function (req, res){
      jwt2.verify(req.token, 'secretkey', (err, auth) => {
        if(err){
          res.sendStatus(403);
        } else {
          res.json({
            message: 'User created (in theory)',
            auth
          })
        }
      })
    });

0
0 Comments

当您的代码在发送响应时多次尝试时,会出现此错误,
这是您的工作后API代码

 app.post('/users/:id', verifyToken, function (req, res){
  jwt2.verify(req.token, 'secretkey', (err, auth) =>{
    if(err){
      res.sendStatus(403);
    } else {
      res.json({
        message: 'User created (in theory)',
        auth
      })
    }
  })
});

只需从该API中删除额外的响应代码

您必须在验证令牌函数中删除next()关键字

function verifyToken(req, res, next){
  // Get auth header value
  const bearerHeader = req.headers['authorization'];
  // Check if bearer is undefined
  if(typeof bearerHeader !== 'undefined'){
    // Split at the space
    const bearer = bearerHeader.split(' ');
    // Get token from array
    const bearerToken = bearer[1];
    // Set the token
    req.token = bearerToken;
    // Next middleware
    next();
  }
    else{
      // Forbidden
      res.sendStatus(403);
    }
  }

使用此代码更新验证函数

0