Express:[ERR_HTTP_HEADERS_SENT]:将标头发送到客户端后无法设置标头

时间:2019-08-02 17:23:02

标签: javascript express jwt express-jwt

我已经阅读了有关同一问题的几篇文章,但无法弄清楚最初将标头发送到何处。这是堆栈跟踪:

当我在数据库中添加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.jsauthService.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%肯定。该代码确实一直进行到最后,并在对用户进行身份验证后将收藏夹插入数据库中,但是随后引发有关标头的错误。

1 个答案:

答案 0 :(得分:0)

问题在于,在patch路线的最后,我有一个next()。一旦我删除了它,它就可以正常工作。