ERR_HTTP_HEADERS_SENT: невозможно установить заголовки после их отправки клиенту

Я столкнулся с этой странной проблемой в NodeJS при использовании с Passport.js, Express и Mongoose. Обычно я получаю сообщение об ошибке «Невозможно установить заголовки после их отправки клиенту», хотя я не отправляю более одного заголовка.

Я читал другие сообщения и пробовал их, но ни один из них не работал.

Я разобрался с проблемами github и не могу найти решения. Проблема заключается в том, что эта ошибка возникает, когда я отправляю несколько заголовков ответов, но факт в том, что я не отправляю несколько заголовков. Это кажется просто странным.

Это моя трассировка стека:

(узел: 9236) DeprecationWarning: текущий синтаксический анализатор строки URL устарел и будет удален в будущей версии. Чтобы использовать новый синтаксический анализатор, передайте параметр {useNewUrlParser: true} в MongoClient.connect.

Сервер работает на порту 5000
Ошибка подключения MongoDB
[ERR_HTTP_HEADERS_SENT]: не удается установить заголовки после их отправки клиенту
в validateHeader (_http_outgoing.js: 503: 11)
в ServerResponse.setHeader ( _http_outgoing.js: 510: 3)
на ServerResponse.header (/Users/lourdesroashan/code/github/devlog/node_modules/express/lib/response.js:767:10)
на ServerResponse.json (/ Пользователи / lourdesroashan / code / github / devlog / node_modules / express / lib / response.js: 264: 10)
в Profile.findOne.then.profile (/ Users / lourdesroashan / code / github / devlog / routes / api /profile.js:27:30)
на ‹anonymous›

Это мой серверный код:

router.get("/userprofile", passport.authenticate('jwt', { session: false }), (req, res) => {

  Profile.findOne({ user: req.user.id }).then(profile => {
    if (!profile) {
      return res.status(404).json({ error: "No Profile Found" });
    }
    else {
      res.json(profile);
    }
  }).catch(err => {
    console.log(err);
  })
});

Я понимаю, что означает ошибка, но из того, что я знаю, я не думаю, что отправляю несколько заголовков, я даже проверил с помощью console.log, что запущен только один из блоков.

Огромное спасибо заранее! :)

Полный код по адресу: https://github.com/lourdesr/devlog

РЕДАКТИРОВАТЬ:

Я понял. При попытке получить аутентифицированного пользователя возникла проблема с моим файлом password.js. Я забыл использовать return для метода done, который его вызвал. Просто добавил оператор возврата, и он сработал!


person lourdesr    schedule 31.08.2018    source источник
comment
Кажется маловероятным, что код сервера, который вы показываете, вызывает ошибку при отправке заголовков. Должен быть какой-то другой код, вызывающий эту ошибку. Эта конкретная ошибка возникает всякий раз, когда вы пытаетесь отправить более одного ответа на один и тот же запрос, и обычно вызвана неправильным асинхронным кодом.   -  person jfriend00    schedule 31.08.2018
comment
Поскольку вы нашли отдельное решение из предложений jfriend00, опубликуйте свой ответ на свой вопрос и примите его.   -  person Patrick M    schedule 17.01.2019


Ответы (8)


Эта конкретная ошибка возникает всякий раз, когда вы пытаетесь отправить более одного ответа на один и тот же запрос, и обычно вызвана неправильным асинхронным кодом.

Код, который вы показываете в своем вопросе, не выглядит так, как будто он может вызвать эту ошибку, но я вижу код в другом маршруте здесь, которая может вызвать эту ошибку.

Где у вас это:

if (!user) {
  errors.email = "User not found";
  res.status(404).json({ errors });
}

Вам нужно изменить его на:

if (!user) {
  errors.email = "User not found";
  res.status(404).json({ errors });
  // stop further execution in this callback
  return;
}

Вы не хотите, чтобы код продолжался после res.status(404).json({ errors });, потому что тогда он попытается отправить другой ответ.


К тому же везде у вас такое:

if (err) throw err;

внутри асинхронного обратного вызова вам нужно заменить его чем-то, что действительно отправляет ответ об ошибке, например:

if (err) {
    console.log(err);
    res.sendStatus(500);
    return;
}

бросание внутри асинхронного обратного вызова просто возвращается в систему событий node.js и не выбрасывается куда-либо, где вы действительно можете его поймать. Кроме того, он не отправляет ответ на HTTP-запрос. Другими словами, он на самом деле не делает того, что должен делать сервер. Так что сделайте себе одолжение и никогда не пишите этот код на своем сервере. Когда вы получаете сообщение об ошибке, отправьте ответ об ошибке.


Поскольку похоже, что вы здесь новичок, я хотел бы поблагодарить вас за включение ссылки на полный исходный код на https://github.com/lourdesr/devlog, потому что только взглянув на него, я смог увидеть это место, где возникает ошибка.

person jfriend00    schedule 31.08.2018
comment
@lourdesr - Это вам объяснило и ответило на ваш вопрос? - person jfriend00; 02.09.2018
comment
Это дало гораздо больше разъяснений. Однако через несколько часов я смог разобраться в проблеме. Он скрывался в моем файле password.js при попытке получить аутентифицированного пользователя - я не добавлял оператор возврата в один из методов done, это вызвало ошибку с несколькими заголовками. Спасибо за помощь! - person lourdesr; 04.09.2018
comment
Отлично, вы прояснили проблему. - person Zeinab; 02.08.2020
comment
спасибо за объяснение :) - person Mr.P; 05.01.2021
comment
Это хороший пример ловушек, которые использовались в Node до _1 _ / _ 2_. - person Andy; 11.03.2021

Я получил эту ошибку из-за моей глупой ошибки. Мне нужно быть более осторожным, когда я ссылаюсь на другой рабочий код. По-настоящему смущает то, как долго я пытался выяснить причину ошибки. Ой!

Плохо:

return res
  .send(C.Status.OK)
  .json({ item });

Хорошо:

return res
  .status(C.Status.OK)
  .json({ item });
person Chunky Chunk    schedule 05.08.2019
comment
Я не вижу разницы между твоим хорошим и плохим примером. @ TheDarkIn1978 - person Author; 15.01.2020
comment
Разница в плохом примере, который я вызываю .send("ok"), в то время как в хорошем примере я вызываю .status("ok"). Цепочка вызовов .json после .send вызвала ошибку. Это была неосторожная ошибка копирования / вставки из другого моего кода. - person Chunky Chunk; 15.01.2020
comment
Вы спасли меня! - person GI HYUN NAM; 18.08.2020

Извините за запоздалый ответ, согласно документации мангуста «Запросы Mongoose не являются обещаниями. У них есть функция .then () для co и async / await для удобства. Однако, в отличие от обещаний, вызов запроса .then () может выполняться запрос несколько раз "

так что использовать обещания

mongoose.Promise = global.Promise //To use the native js promises

потом

var promise = Profile.findOne({ user: req.user.id }).exec()
promise.then(function (profile){
    if (!profile) {
      throw new Error("User profile not found") //reject promise with error
    }
    return res.status(200).json(profile) //return user profile      
}).catch(function (err){
    console.log(err); //User profile not found
    return res.status(404).json({ err.message }) //return your error msg
})

вот хорошая статья о переключении обратных вызовов с помощью обещаний в Mongoose < / а>

и этот ответ на мангустах, обрабатывающих отклонение обещаний, Обработка отклонения правого обещания Mongoose

person Ivan of uganda    schedule 09.05.2019

Из-за отправки множественного ответа на ваш запрос. если вы используете ключевое слово return в своем условии else, ваш код будет работать правильно

if (!profile) {
    return res.status(404).json({ error: "No Profile Found" });
}
else {
    **return** res.json(profile);
}
person Saeed Awan    schedule 14.12.2020

Я получил ту же ошибку, используя экспресс и мангуст с механизмом шаблонов HBS. Я пошел в Expressjs и прочитал документацию для res.render, и там написано, // что если задан обратный вызов, визуализированная строка HTML должна быть отправлена ​​явно. Поэтому я изначально не отправлял свой html явно в обратном вызове. Кстати, это только для контактной формы, а не для входа в систему, хотя ПОЛУЧИТЬ

//Original
let { username, email } = req.query;  //My get query data easier to read

res.status(200).render('index', { username, email });

//Solution without error. Second param sending data to views, Third param callback

res.status(200).render('index', { username, email }, (err, html)=>{
      res.send(html);
 });
person Community    schedule 14.08.2019

Существует простое исправление ошибки узла [ERR_HTTP_HEADERS_SET]. Вам нужно добавить оператор return перед вашими ответами, чтобы убедиться, что ваш маршрутизатор правильно завершает работу при ошибке:

router.post("/", async (req, res) => {
    
    let user = await User.findOne({email: req.body.email});   
    if (!user) **return** res.status(400).send("Wrong user");
    
});
person Eugène Beliaev    schedule 15.12.2020

Используйте горячую клавишу ctrl + F и найдите все «res». ключевые слова, затем замените их префиксом 'return',

change  all 'res.' to  'return res.'

что-то вроде этого:

res.send () изменить на - ›return res.send ()

может быть, у вас есть "res". в каком-то блоке, например, if ()

person Mohammad Reza Mrg    schedule 06.05.2021

вы должны включить Promises в своей программе, в моем случае я включил его в своей схеме мангуста, используя mongoose.Promise = global.Promise. Это позволяет использовать native js promises.

другие альтернативы этому решению:

var mongoose = require('mongoose');
// set Promise provider to bluebird
mongoose.Promise = require('bluebird');

а также

// q
mongoose.Promise = require('q').Promise;

но сначала вам нужно установить эти пакеты.

person sina    schedule 11.02.2020