Помилка. Неможливо встановити заголовки після їх надсилання клієнту


724

Я досить новачок у Node.js, і у мене виникають деякі проблеми.

Я використовую Node.js 4.10 та Express 2.4.3.

Коли я спробую отримати доступ до http://127.0.0.1:8888/auth/facebook , я буду перенаправлений на http://127.0.0.1:8888/auth/facebook_callback .

Потім я отримав таку помилку:

Error: Can't render headers after they are sent to the client.
    at ServerResponse.<anonymous> (http.js:573:11)
    at ServerResponse._renderHeaders (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:64:25)
    at ServerResponse.writeHead (http.js:813:20)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:28:15
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:113:13
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/strategyExecutor.js:45:39)
    at [object Object].pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:32:3)
    at [object Object].halt (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:29:8)
    at [object Object].redirect (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:16:8)
    at [object Object].<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:77:15)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:195:11)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
    at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
    at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
    at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
    at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
    at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
    at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9

node.js:134
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9
    at Array.<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session/memory.js:57:7)
    at EventEmitter._tickCallback (node.js:126:26)

Наступний мій код:

var fbId= "XXX";
var fbSecret= "XXXXXX";
var fbCallbackAddress= "http://127.0.0.1:8888/auth/facebook_callback"

var cookieSecret = "node";     // enter a random hash for security

var express= require('express');
var auth = require('connect-auth')
var app = express.createServer();


app.configure(function(){
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.session({secret: cookieSecret}));
    app.use(auth([
        auth.Facebook({
            appId : fbId,
            appSecret: fbSecret,
            callback: fbCallbackAddress,
            scope: 'offline_access,email,user_about_me,user_activities,manage_pages,publish_stream',
            failedUri: '/noauth'
        })
    ]));
    app.use(app.router);
});


app.get('/auth/facebook', function(req, res) {
  req.authenticate("facebook", function(error, authenticated) {
    if (authenticated) {
      res.redirect("/great");
      console.log("ok cool.");
      console.log(res['req']['session']);
    }
  });
});

app.get('/noauth', function(req, res) {
  console.log('Authentication Failed');
  res.send('Authentication Failed');
});

app.get('/great', function( req, res) {
  res.send('Supercoolstuff');
});

app.listen(8888);

Чи можу я знати, що з моїм кодом не так?


проста відповідь від visionmedia: github.com/visionmedia/express/isissue/634
shi11i

2
Google надіслав мені це питання, але новіші версії ExpressJS мають res.headersSent boolean, які можна перевірити, чи безпечно встановлювати / надсилати заголовки
Julian Soro

Відповіді:


1112

resОб'єкт Експрес підклас Node.js - хhttp.ServerResponse ( читати джерело http.js ). Вам дозволяється дзвонити res.setHeader(name, value)так часто, як вам потрібно, доки ви не зателефонуєте res.writeHead(statusCode). Після writeHeadцього заголовки запікаються, і ви можете лише зателефонувати res.write(data), і нарешті res.end(data).

Помилка "Помилка. Неможливо встановити заголовки після їх надсилання." означає, що ви вже перебуваєте в стані Body або Finished, але деяка функція намагалася встановити заголовок або statusCode. Коли ви побачите цю помилку, спробуйте пошукати все, що намагається надіслати заголовок після того, як частина тіла вже написана. Наприклад, шукайте зворотні дзвінки, які випадково викликаються двічі, або помилки, що трапляються після надсилання тіла.

У вашому випадку ви подзвонили res.redirect(), через що відповідь закінчилася. Тоді ваш код кинув помилку ( res.reqє null). а оскільки помилка трапилася в межах вашої фактичної function(req, res, next)(не в межах зворотного дзвінка), Connect змогла її виявити, а потім спробувала надіслати сторінку 500 помилок. Але оскільки заголовки вже надіслані, Node.js setHeaderвикинув помилку, яку ви побачили.

Повний список методів відповіді Node.js / Express та коли їх потрібно викликати:

Відповідь має бути в голові та залишатися в голові :

  1. res.writeContinue()
  2. res.statusCode = 404
  3. res.setHeader(name, value)
  4. res.getHeader(name)
  5. res.removeHeader(name)
  6. res.header(key[, val]) (Лише експрес)
  7. res.charset = 'utf-8' (Тільки експрес; впливає лише на експрес-методи)
  8. res.contentType(type) (Лише експрес)

Відповідь має бути в голові і стає Органом :

  1. res.writeHead(statusCode, [reasonPhrase], [headers])

Відповідь може бути як у голові / тілі, так і залишатися в тілі :

  1. res.write(chunk, encoding='utf8')

Відповідь може бути в будь-якій голові / тілі і стає Готовою :

  1. res.end([data], [encoding])

Відповідь може бути як у керівника / органу, так і залишається в поточному стані:

  1. res.addTrailers(headers)

Відповідь має бути в голові і стає Готовим :

  1. return next([err]) (Лише підключення / експрес)
  2. Будь-які винятки в межах проміжного програмного забезпечення function(req, res, next)(лише для Connect / Express)
  3. res.send(body|status[, headers|status[, status]]) (Лише експрес)
  4. res.attachment(filename) (Лише експрес)
  5. res.sendfile(path[, options[, callback]]) (Лише експрес)
  6. res.json(obj[, headers|status[, status]]) (Лише експрес)
  7. res.redirect(url[, status]) (Лише експрес)
  8. res.cookie(name, val[, options]) (Лише експрес)
  9. res.clearCookie(name[, options]) (Лише експрес)
  10. res.render(view[, options[, fn]]) (Лише експрес)
  11. res.partial(view[, options]) (Лише експрес)

13
Так, двічі перевірте, чи дзвонить наступний () або інший веб-сайт.
Тоні Гутьеррес

3
Експрес-посилання здається мертвим
Корхан Озтурк

25
також стежте за цією класичною помилкою: res.redirect () не зупиняє виконання оператора ... тому поверніться після нього. В іншому випадку може бути виконаний інший код, який може ненавмисно викликати відому помилку заголовка. Дякую за пояснення!
KLoozen

Зазвичай корисно використовувати повернення в кінці зворотного дзвінка, щоб уникнути цього
thethakuri

4
Я зробив дуже маленьку помилку в своєму середньому програмному забезпеченні, я returnраніше next()цього не робив , дякую, це вказало мені на помилку!
illcrx

113

Я натрапив на цю помилку також на деякий час. Я думаю (сподіваюсь) я обернув голову навколо цього, хотів написати це тут для довідки.

Коли ви додаєте проміжне програмне забезпечення для підключення або вираження (яке побудовано на підключенні) за допомогою app.useметоду, ви додаєте елементи до Server.prototype.stackз'єднання (принаймні до поточного npm install connect, який виглядає зовсім інакше, ніж один github, як у цій публікації). Коли сервер отримує запит, він повторюється через стек, викликаючи (request, response, next)метод.

Проблема полягає в тому, що якщо в одному з програм проміжного програмного забезпечення пишеться в тіло відповіді або заголовки (схоже, це або / або з якихось причин), але він не дзвонить, response.end()аnext() потім дзвонить, коли основний Server.prototype.handleметод завершиться, він помітить що:

  1. в стеку немає більше елементів та / або
  2. що response.headerSentце правда.

Отже, це кидає помилку. Але помилка, яку він видає, - це саме ця основна відповідь (з http.jsвихідного коду підключення :

res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('Cannot ' + req.method + ' ' + req.url);

Тут же виклик res.setHeader('Content-Type', 'text/plain');, який ви, ймовірно, встановили у своєму renderметоді, не викликаючи відповідь.end () , щось на кшталт:

response.setHeader("Content-Type", "text/html");
response.write("<p>Hello World</p>");

Спосіб структуризації має бути таким:

Хороше середнє програмне забезпечення

// middleware that does not modify the response body
var doesNotModifyBody = function(request, response, next) {
  request.params = {
    a: "b"
  };
  // calls next because it hasn't modified the header
  next();
};

// middleware that modify the response body
var doesModifyBody = function(request, response, next) {
  response.setHeader("Content-Type", "text/html");
  response.write("<p>Hello World</p>");
  response.end();
  // doesn't call next()
};

app.use(doesNotModifyBody);
app.use(doesModifyBody);

Проблемне програмне забезпечення

var problemMiddleware = function(request, response, next) {
  response.setHeader("Content-Type", "text/html");
  response.write("<p>Hello World</p>");
  next();
};

Проблемне проміжне програмне забезпечення встановлює заголовок відповіді без викликів response.end()та дзвінків next(), що плутає сервер з'єднання.


7
+1 Це чудове пояснення, але як бути з випадком, коли ви використовуєте res.redirect ()? Я часто стикаюся з цією проблемою, коли середнє програмне забезпечення намагається перенаправити на основі певної умови. Якщо середнє програмне забезпечення не повинно переспрямовуватись за вашим прикладом "Good Middleware"?
qodeninja

Ви знаєте, що у мене є така точна проблема через те, що ви називаєте проблемним проміжним програмним забезпеченням, проте мені потрібен випадок, коли я повертаю відповідь, але хотів би зробити подальшу обробку в окремому контролері як частину ланцюга, як мені піти на придушення цієї помилки ?
iQ.

57

Деякі відповіді в цьому запитанні не відповідають питанням. Прийнята відповідь також не дуже "практична", тому я хочу опублікувати відповідь, яка пояснює речі простішими термінами. Моя відповідь охоплює 99% помилок, які я бачу знову і знову. З фактичних причин помилки подивіться на прийняту відповідь.


HTTP використовує цикл, який вимагає однієї відповіді на запит. Коли клієнт надсилає запит (наприклад, POST або GET), сервер повинен надіслати йому лише одну відповідь.

Це повідомлення про помилку:

Помилка. Неможливо встановити заголовки після їх надсилання.

зазвичай відбувається, коли ви надсилаєте кілька відповідей на один запит. Переконайтеся, що такі функції викликаються лише один раз на запит:

  • res.json()
  • res.send()
  • res.redirect()
  • res.render()

(та ще кілька, які рідко використовуються, перевірте прийняту відповідь)

Зворотний виклик маршруту не повернеться, коли викликаються ці функції res. Він буде тривати до тих пір, поки не потрапить до кінця функції або оператора return. Якщо ви хочете повернутися при написанні відповіді ви можете зробити це так: 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, він запустить кожен рядок у зворотному дзвінку . Не може встановити заголовки після відправки повідомлення про помилку буде відкинута , так як 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 }).


2
Ви в асинхронної функції, і повиненreturnres.json
Genovo

Моя проблема використовувалась res.sendдля циклу.
Майхан Ніджат

1
Це допомогло мені врешті-решт зрозуміти та виправити проблему. Дякую багато :)
Панкай Паркяр

дякую тобі, що ти економиш мій час.
Мохаммед Файсал

Це, безумовно, найкраща відповідь!
Хуанма Менендес

53

У мене був цей самий випуск, і я зрозумів, що це було тому, що я дзвонив res.redirectбез returnзаяви, тому nextфункцію також викликали відразу після цього:

auth.annonymousOnly = function(req, res, next) {
    if (req.user) res.redirect('/');
    next();
};

Що мали бути:

auth.annonymousOnly = function(req, res, next) {
    if (req.user) return res.redirect('/');
    next();
};

43

До цієї помилки потрапило багато людей. Це плутає це з асинхронною обробкою. Швидше за все, якийсь ваш код встановлює заголовки в першій галочці, а потім ви виконуєте зворотний виклик асинхронізації в майбутньому галочці. Між тим надсилається заголовок відповіді, але потім додаткові заголовки (як перенаправлення 30X) намагаються додати додаткові заголовки, але це вже пізно, оскільки заголовок відповіді вже передано.

Я не впевнений, що саме викликає вашу помилку, але розглядайте будь-які зворотні дзвінки як потенційні сфери для дослідження.

Один простий підказки для спрощення коду. Позбудьтесь app.configure()та просто зателефонуйте app.useбезпосередньо у межах свого найвищого рівня.

Дивіться також модуль Everyauth , який здійснює Facebook та ще десяток інших постачальників аутентифікації.


Переадресація 30X - це код відповіді HTTP. w3.org/Protocols/rfc2616/rfc2616-sec10.html Коди 300-399 є різними варіантами переадресації, причому 302 та 301 зазвичай використовуються для надсилання клієнта на альтернативну URL-адресу. Коли ви виконаєте response.redirect (...) у вузлі, у відповідь буде надісланий заголовок переадресації 30X.
Пітер Ліонс

3
Оххх. Я уявляв 30 переадресацій поспіль чи щось таке
Janac Meena

17

Я кинув головою над цією проблемою, і це сталося через необережну помилку в обробці зворотних дзвінків. неповернені дзвінки викликають, що відповідь встановлюється двічі.!

У моїй програмі був код, який підтверджує запит і запитує БД. після перевірки, якщо помилка є, я передзвонив index.js з помилками перевірки. І якщо перевірка пройде, вона рухається вперед і ударяє db з успіхом / невдачею.

    var error = validateRequestDetails("create",queryReq);
    if (error)
        callback(error, null);
   else
    some code 
    callback(null, success);

Те, що відбувалося, таке: перевірка обкладинки не дає змоги викликати зворотний виклик та встановити відповідь. Але не повернувся. Тож він все ще продовжує метод переходити до db і вражати успіх / провал. Він викликає той самий зворотний дзвінок знову, викликаючи відповідь, яку зараз встановлюють двічі.

Тому рішення просте, вам потрібно 'повернути' зворотний виклик, щоб метод не продовжував виконуватись, як тільки помилка сталася, а значить, один раз встановити об'єкт відповіді

  var error = validateRequestDetails("create",queryReq);
    if (error)
        callback(error, null);
        return;
    else
       some code 
       callback(null, success);

1
Дякую! Це виявилося і моєю проблемою. Просто зробив ctrl + f і знайшов a callback(...)без return;нього, що в кінцевому підсумку викликало res.send(...)виклик двічі.

15

Цей тип помилок ви отримаєте при передачі заяви після надсилання відповіді.

Наприклад:

res.send("something response");
console.log("jhgfjhgsdhgfsdf");
console.log("sdgsdfhdgfdhgsdf");
res.send("sopmething response");

Це призведе до помилки, яку ви бачите, оскільки після того, як відповідь буде надіслана, наступне res.sendне буде виконано.

Якщо ви хочете зробити що-небудь, ви повинні зробити це, перш ніж надсилати відповідь.


Це був мій точний випуск :)
Joel Balmer

6

Іноді ви можете отримати цю помилку під час спроби викликати функцію next () після res.end або res.send , спробуйте видалити, якщо у вас функція next () після res.send або res.end у вашій функції. Примітка: тут next () означає, що після відповіді на клієнта вашою відповіддю ( тобто res.send або res.end ) ви все ще намагаєтесь виконати якийсь код, щоб відповісти ще раз, щоб це не було законно.

Приклад:

router.get('/',function (req,res,next){
     res.send("request received");
     next(); // this will give you the above exception 
});

видаліть next()зверху функцію, і вона буде працювати.


6

Якщо ви використовуєте функції зворотного дзвінка, використовуйте returnпісля errблоку. Це один із сценаріїв, коли ця помилка може статися.

userModel.createUser(data, function(err, data) {
    if(err) {
      res.status = 422
      res.json(err)
      return // without this return the error can happen.
    }
    return res.json(data)
  })

Тестовано у версії Node v10.16.0та express4.16.4


4

Ця помилка трапляється, коли ви надсилаєте 2 відповіді. Наприклад :

if(condition A)
{ 

      res.render('Profile', {client:client_});

}

if (condition B){

      res.render('Profile', {client:client_});
    }
  }

Уявіть, якщо з якихось причин умови A і B вірні, тому в другій renderви отримаєте цю помилку


3

У моєму випадку проблема була 304 відповіді (кешування).

Найпростіше рішення:

app.disable('etag');

Альтернативне рішення тут, якщо ви хочете отримати більше контролю:

http://vlasenko.org/2011/10/12/expressconnect-static-set-last-modified-to-now-to-avoid-304-not-modified/


У моєму випадку також 304 відповіді. Я використовую волокна для обробки. Будь-який спосіб вашої відповіді дуже допомагає. дякую
Dileep Stanley

Чи може хтось пояснити, які наслідки мають для видалення заголовка етагу?
mattwilsn

2
ETags дозволяють серверу не надсилати вміст, який не змінився. Вимкнення цієї функції відключає цю функцію. Запис у вікіпедії ETag ( en.wikipedia.org/wiki/HTTP_ETag ) має більш тривале пояснення.
Бланширована

3

У моєму випадку це сталося з React та Postal.js, коли я не скасував підписку на канал у componentWillUnmountзворотному дзвінку мого компонента React.


2

Для тих, хто приходить до цього, і жодне з інших рішень не допомогло, в моєму випадку це проявилося на маршруті, який обробляв завантаження зображення, але не обробляв тайм-аути , а отже, якщо завантаження зайняло занадто багато часу та вичерпано час, коли зворотний виклик був знятий після відправлення відповіді на час очікування виклик res.send () призвів до збоїв, оскільки заголовки вже були налаштовані для обліку часу очікування.

Це було легко відтворено, встановивши дуже короткий час очікування та вдаривши по маршруту з пристойно-великим зображенням, збій відтворювався щоразу.


1
як ви впоралися з тайм-аутом, щоб уникнути цього?

2

Просто нахилився до цього. Ви можете передавати відповіді за допомогою цієї функції:

app.use(function(req,res,next){
  var _send = res.send;
  var sent = false;
  res.send = function(data){
    if(sent) return;
    _send.bind(res)(data);
    sent = true;
};
  next();
});

2

Додайте це середнє програмне забезпечення, і воно спрацює

app.use(function(req,res,next){
 var _send = res.send;
var sent = false;
res.send = function(data){
    if(sent) return;
    _send.bind(res)(data);
    sent = true;
};
next();
});

2

Це відбувається, коли відповідь була доставлена ​​клієнтові, і ви знову намагаєтесь дати відповідь. Ви повинні перевірити у своєму коді, що десь ви знову повертаєте відповідь клієнту, що викликає цю помилку. Перевірте та поверніть відповідь один раз, коли ви хочете повернутися.


1

У мене виникло це питання, коли я вкладав обіцянки. Обіцянка всередині обіцянки поверне 200 на сервер, але тоді зовнішня заява про вилов обіцянки поверне 500. Після того, як я це виправив, проблема пішла.


як саме ви це виправили? У мене те саме питання з обіцянками. Я не можу уникнути їх вкладення ... так як я зупиняю виконання при операторі return?
saurabh

1

Прийшов сюди з nuxt , проблема полягала в asyncDataметоді компонента , я забув returnпообіцяти, який там буде отримання даних і встановлення заголовка.


1

Перевірте, чи повертає ваш код кілька заяв res.send () для одного запиту. Як колись у мене виникло це питання ...

Ця проблема була в моєму застосуванні для вузла restify. Помилка полягала в тому

switch (status) { case -1: res.send(400); case 0: res.send(200); default: res.send(500); }

Я обробляв різні випадки за допомогою перемикача без перерви в роботі. Для тих, хто мало знайомий із випадком комутації, знайте, що без перерви повертайте ключові слова. Код під регістром та наступні рядки його будуть виконуватися незалежно від того. Тож хоч я хочу надіслати один res.send, через цю помилку він повертав кілька заявок res.send, що підказувало

помилка не може встановити заголовки після їх надсилання клієнту. Що було вирішено шляхом додавання цього або використання return перед кожним методом res.send (), як return res.send (200)

switch (status) { case -1: res.send(400); break; case 0: res.send(200); break; default: res.send(500); break; }


дякую за ваше натхнення, як і зі мною. Я вирішив це також і з іншим, якщо за умови
Amr AbdelRahman

1

Цілком ймовірно, що це скоріше річ із вузлом, у 99% випадків це подвійний зворотний виклик, що змушує вас відповісти двічі або наступний () раз двічі і т. Д., Чорт упевнений. Це вирішило мою проблему з використанням next () всередині циклу. Вийміть наступний () з циклу або припиніть його дзвінок не один раз.


1

Я отримав подібну помилку, коли спробував надіслати відповідь у межах функції циклу. Простим рішенням було переміщення

res.send ('надіслати відповідь');

з циклу, оскільки ви можете надіслати заголовок відповіді лише один раз.

https://www.tutorialspoint.com/nodejs/nodejs_response_object.htm



1

У мене була така ж проблема, яку викликав мангуст.

щоб виправити, що потрібно активувати 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;

але вам потрібно спочатку встановити ці пакети.


1

помилка пошуку сама після RND:

1) мій код помилки:

return res.sendStatus(200).json({ data: result });

2) мій код успіху

return res.status(200).json({ data: result });

різниця полягає в тому, що я використовував sendStatus () замість статусу () .


0

У Typescript моя проблема полягала в тому, що я не закрив з'єднання веб-розетки після отримання повідомлення.

WebSocket.on("message", (data) => {
    receivedMessage = true;
    doSomething(data);
    localSocket.close(); //This close the connection, allowing 
});

0

Якщо ви не отримуєте допомоги зверху: для noobs Причиною цієї помилки є надсилання запиту кілька разів, дайте нам зрозуміти з деяких випадків: - 1. `

module.exports = (req,res,next)=>{
        try{
           const decoded  = jwt.verify(req.body.token,"secret");
           req.userData = decoded;
           next();
        }catch(error){
            return res.status(401).json({message:'Auth failed'});
        }
        next();   
        }

`у вищезазначеному дзвінку next () двічі призведе до помилки

  1. router.delete('/:orderId', (req, res, next) => { Order.remove({_id:req.params.orderId},(err,data)=>{ if(err){ **res.status(500).json(err);** }else{ res.status(200).json(data); } *res.status(200).json(data);* }) })

тут відповідь - надіслати двічі, перевірте, чи вже ви надіслали відповідь


0

У моєму випадку це відбувається через безліч зворотних дзвінків. Я називав next()метод кілька разів під час коду


0

Моя проблема полягала в тому, що у мене був setIntervalзапуск, який мав if/elseблок, де clearIntervalметод знаходився всередині else:

      const dataExistsInterval = setInterval(async () => {
        const dataExists = Object.keys(req.body).length !== 0;
        if (dataExists) {
          if (!req.files.length) {
            return res.json({ msg: false });
          } else {
              clearInterval(dataExistsInterval);
            try {
            . . .

Поставивши clearIntervalперед тим, що if/elseзробив трюк.



-1

Все, що мені потрібно було зробити у випадку цієї помилки, було res.end ().

 auth.annonymousOnly = function(req, res, next) {
 // add other task here   
   res.end();    
  };

Інша проблема, з якою ви можете зіткнутися, - це код після res.json та res. писати. У цьому випадку вам потрібно використовувати return, щоб зупинити виконання після цього.

 auth.annonymousOnly = function(req, res, next) {

  if(!req.body.name)
  {
    res.json({error:"some error"});
    return;
  }
  let comp = "value"; // this is the code after res.json which may cause some problems so you have to use return 
};
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.