Некоторые ответы в этом вопросе и ответах неверны.Принятый ответ также не очень «практичен», поэтому я хочу опубликовать ответ, который объясняет вещи в более простых терминах.Мой ответ покроет 99% ошибок, которые я вижу, опубликованные снова и снова.По фактическим причинам ошибки посмотрите на принятый ответ.
HTTP использует цикл, который требует один ответ на запрос.Когда клиент отправляет запрос (например, POST или GET), сервер должен отправить ему только один ответ.
Это сообщение об ошибке:
Ошибка: невозможно установить заголовки послеони отправляются.
обычно происходит, когда вы отправляете несколько ответов на один запрос.Убедитесь, что следующие функции вызываются только один раз для запроса:
res.json()
res.send()
res.redirect()
res.render()
(и еще несколько редко используемых, проверьте принятый ответ)
Обратный вызов маршрута не вернется, когдаэти функции res называются.Он будет продолжать работать до тех пор, пока не достигнет конца функции или оператора возврата.Если вы хотите вернуться при отправке ответа, вы можете сделать это так: return res.send()
.
Возьмите, например, этот код:
app.post('/api/route1', function(req, res) {
console.log('this ran');
res.status(200).json({ message: 'ok' });
console.log('this ran too');
res.status(200).json({ message: 'ok' });
}
Когда отправляется запрос POSTна / api / route1 он будет запускать каждую строку в обратном вызове.A Невозможно установить заголовки после их отправки. Будет выдано сообщение об ошибке, поскольку res.json()
вызывается дважды, что означает отправку двух ответов.
Можно отправить только один ответза запрос!
Ошибка в приведенном выше примере кода была очевидной.Более типичная проблема - когда у вас несколько филиалов:
app.get('/api/company/:companyId', function(req, res) {
const { companyId } = req.params;
Company.findById(companyId).exec((err, company) => {
if (err) {
res.status(500).json(err);
} else if (!company) {
res.status(404).json(); // This runs.
}
res.status(200).json(company); // This runs as well.
});
}
Этот маршрут с прикрепленным обратным вызовом находит компанию в базе данных.При выполнении запроса для несуществующей компании мы попадем в ветку else if
и отправим ответ 404.После этого мы перейдем к следующему утверждению, которое также отправляет ответ.Теперь мы отправили два ответа и появится сообщение об ошибке.Мы можем исправить этот код, убедившись, что отправляем только один ответ:
.exec((err, company) => {
if (err) {
res.status(500).json(err);
} else if (!company) {
res.status(404).json(); // Only this runs.
} else {
res.status(200).json(company);
}
});
или возвращая при отправке ответа:
.exec((err, company) => {
if (err) {
return res.status(500).json(err);
} else if (!company) {
return res.status(404).json(); // Only this runs.
}
return res.status(200).json(company);
});
Большой грешник - асинхронные функции,Возьмите функцию из этого вопроса, например:
article.save(function(err, doc1) {
if (err) {
res.send(err);
} else {
User.findOneAndUpdate({ _id: req.user._id }, { $push: { article: doc._id } })
.exec(function(err, doc2) {
if (err) res.send(err);
else res.json(doc2); // Will be called second.
})
res.json(doc1); // Will be called first.
}
});
Здесь мы имеем асинхронную функцию (findOneAndUpdate()
) в примере кода.Если ошибок нет (err
), будет вызван findOneAndUpdate()
.Поскольку эта функция асинхронная, res.json(doc1)
будет вызван немедленно.Предположим, что в findOneAndUpdate()
нет ошибок.Затем будет вызван res.json(doc2)
в else
.Теперь отправлено два ответа, и появляется сообщение об ошибке Не удается установить заголовки .
В этом случае исправлением будет удаление res.json(doc1)
.Чтобы отправить оба документа клиенту, res.json()
в другом можно записать как res.json({ article: doc1, user: doc2 })
.