Node.js,Express:在将响应发送给客户端后无法设置标题
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日
在你的代码 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 }) } }) });
当您的代码在发送响应时多次尝试时,会出现此错误,
这是您的工作后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); } }
使用此代码更新验证函数