我已经阅读了有关同一问题的几篇文章,但无法弄清楚最初将标头发送到何处。这是堆栈跟踪:
当我在数据库中添加204时,也觉得很奇怪,然后它吐出404。很明显,这是错误的,但我只是没有看到它。
我尝试将返回值添加到每个res.json()
语句中。
OPTIONS /api/users/favorites 204 1.822 ms - 0
PATCH /api/users/favorites 404 19.769 ms - 160
Unhandled rejection Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:455:11)
at ServerResponse.header (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/response.js:771:10)
at ServerResponse.send (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/response.js:267:15)
at /Users/beers/projects/node/cryptopal-api/src/users/usersRouter.js:30:38
From previous event:
at Builder.Target.then (/Users/beers/projects/node/cryptopal-api/node_modules/knex/lib/interface.js:27:24)
at /Users/beers/projects/node/cryptopal-api/src/users/usersRouter.js:19:8
at Layer.handle [as handle_request] (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/route.js:137:13)
at requireAuth (/Users/beers/projects/node/cryptopal-api/src/middleware/jwt-auth.js:31:5)
at Layer.handle [as handle_request] (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/layer.js:95:5)
at /Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/index.js:335:12)
at next (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/index.js:275:10)
at Function.handle (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/index.js:174:3)
at router (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/index.js:47:12)
at Layer.handle [as handle_request] (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/index.js:317:13)
at /Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/index.js:335:12)
at next (/Users/beers/projects/node/cryptopal-api/node_modules/express/lib/router/index.js:275:10)
at /Users/beers/projects/node/cryptopal-api/node_modules/body-parser/lib/read.js:130:5
at invokeCallback (/Users/beers/projects/node/cryptopal-api/node_modules/raw-body/index.js:224:16)
at done (/Users/beers/projects/node/cryptopal-api/node_modules/raw-body/index.js:213:7)
at IncomingMessage.onEnd (/Users/beers/projects/node/cryptopal-api/node_modules/raw-body/index.js:273:7)
at IncomingMessage.emit (events.js:205:15)
at endReadableNT (_stream_readable.js:1154:12)
这是我的usersRouter.js
require('dotenv').config();
const express = require('express');
// const rp = require('request-promise');
const usersRouter = express.Router()
const jsonParser = express.json()
const UsersService = require('./usersService.js')
const { requireAuth } = require('../middleware/jwt-auth.js')
usersRouter
.patch('/favorites', requireAuth, (req,res,next) => {
const db = req.app.get('db');
const { coinID } = req.body;
const { user_id } = req;
console.log(res.headersSent) // EQUALS FALSE
// get current favorites for user to see if it already exists in db
UsersService.getUserFavorites(db, user_id)
.then( response => {
console.log(res.headersSent) // EQUALS TRUE
let favExists = false;
response.favorites.forEach( fav => {
if(fav == coinID)
favExists = true;
})
if(favExists){
return res.status(401).json({ error: "Coin already exists in favorites" })
}else{
UsersService.addToUserFavorites(db, user_id, coinID)
.then( response => {
return res.status(204).json({ response })
})
}
})
next()
});
module.exports = usersRouter;
如您所见,patch
路由在添加收藏夹之前调用中间件函数requireAuth
对用户进行身份验证。
这是文件jwt-auth.js
const AuthService = require('../auth/authService.js')
function requireAuth(req, res, next) {
const authToken = req.get('Authorization') || ''
let bearerToken
if (!authToken.toLowerCase().startsWith('bearer ')) {
return res.status(401).json({ error: 'Missing bearer token' })
} else {
bearerToken = authToken.slice(7, authToken.length)
}
try {
const payload = AuthService.verifyJwt(bearerToken);
AuthService.getUserByEmail(
req.app.get('db'),
payload.sub,
)
.then(user => {
if (!user){
return res.status(401).json({ error: 'Unauthorized request' })
}
next();
})
.catch(err => {
console.error(err)
next(err)
})
req.user_id = payload.user_id;
next()
} catch(error) {
return res.status(401).json({ error: 'Unauthorized request' })
}
}
module.exports = {
requireAuth,
}
我还将包括usersService.js
和authService.js
文件,因为其中有几个函数被调用,但是我不认为这就是错误所在。
usersService.js
:
const xss = require('xss');
const config = require('../config.js');
const UsersService = {
getUserByID(db,id){
return db('cryptopal_users')
.where({ id })
.first()
},
getUserFavorites(db,id){
return db('cryptopal_users')
.where('id', id)
.first()
},
addToUserFavorites(db,id,favorites){
return db('cryptopal_users')
.where('id', id)
.update({
favorites: db.raw('array_append(favorites, ?)', [favorites])
})
},
}
module.exports = UsersService;
authService.js
const xss = require('xss');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('../config.js');
const AuthService = {
validatePassword(password){
if(password.length < 6){
return "Password must be at least 6 characters"
}
},
hashPassword(password){
return bcrypt.hash(password,12);
},
comparePasswords(password,hash){
return bcrypt.compare(password,hash);
},
createJwt(subject, payload) {
return jwt.sign(payload, config.JWT_SECRET, {
subject,
expiresIn: config.JWT_EXPIRY,
algorithm: 'HS256',
})
},
checkEmailUnique(db,email){
return db('cryptopal_users')
.where({ email })
.first()
.then(user => !!user)
},
insertUser(db,user){
return db
.insert(user)
.into('cryptopal_users')
.returning('*')
.then( ([user]) => user )
},
serializeUser(user){
return {
id: user.id,
name: xss(user.name),
email: xss(user.email),
date_created: new Date(user.date_created),
}
},
getUserByEmail(db,email){
return db('cryptopal_users')
.where({ email })
.first()
},
verifyJwt(token) {
return jwt.verify(token, config.JWT_SECRET, {
algorithms: ['HS256'],
})
},
}
module.exports = AuthService;
我认为问题出在jwt-auth.js
文件中,但不是100%肯定。该代码确实一直进行到最后,并在对用户进行身份验证后将收藏夹插入数据库中,但是随后引发有关标头的错误。
答案 0 :(得分:0)
问题在于,在patch
路线的最后,我有一个next()
。一旦我删除了它,它就可以正常工作。