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

727

Я довольно новичок в 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);

Могу ли я узнать, что не так с моим кодом?

DjangoRocks
источник
простой ответ от visionmedia: github.com/visionmedia/express/issues/634
shi11i
2
Google послал меня на этот вопрос, но в более новых версиях ExpressJS есть логическое значение res.headersSent, которое можно использовать для проверки безопасности установки / отправки заголовков
Джулиан Соро,

Ответы:

1113

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' (Только Express; влияет только на методы, специфичные для Express)
  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]) (Экспресс только)
yonran
источник
13
Да, проверьте для вызова next () или другого cb дважды.
Тони Гутьеррес
3
Экспресс ссылки кажутся мертвыми
Korhan Ozturk
25
Также следите за этой классической ошибкой: res.redirect () не останавливает выполнение оператора ... так что возвращайтесь после него. В противном случае может быть выполнен другой код, который может непреднамеренно вызвать известную ошибку заголовка. Спасибо за объяснение!
KLoozen
Обычно хорошей идеей является использование return в конце вашего обратного вызова, чтобы избежать этого
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методе, без вызова response.end () , что-то вроде:

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

То, как все должно быть структурировано, выглядит следующим образом:

Хорошее Middleware

// 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 ()? Я часто сталкиваюсь с этой проблемой, когда промежуточное ПО пытается перенаправить на основании какого-либо условия. Должно ли промежуточное ПО не перенаправлять, в соответствии с вашим примером "Хорошего промежуточного ПО"?
qodeninja
Вы знаете, у меня есть именно эта проблема из-за того, что вы называете проблемным промежуточным программным обеспечением, однако мне нужен случай, когда я возвращаю ответ, но хотел бы выполнить дальнейшую обработку в отдельном контроллере как часть цепочки, как я могу устранить эту ошибку ?
IQ.
57

Некоторые из ответов в этом Q & A неправильны. Принятый ответ также не очень «практичен», поэтому я хочу опубликовать ответ, который объясняет вещи в более простых терминах. Мой ответ покроет 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, он запускает каждую строку в обратном вызове . Не может установить заголовки после отправки сообщения об ошибке будет отброшена , так как 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
Это помогло мне в конце понять и решить проблему, спасибо большое :)
Pankaj Parkar
Большое вам спасибо, вы экономите мое время.
Мухаммед Фейсал
Это, безусловно, лучший ответ!
Хуанма Менендес
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();
};
ergusto
источник
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 редиректов подряд или что-то в этом роде
Янак Мина,
17

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

Моя программа имела код, который проверяет запрос и запрашивает БД. после проверки, если есть ошибка, я перезванивал index.js с ошибками проверки. И если проверка проходит успешно, она идет вперед и поражает БД с успехом / неудачей.

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

Происходило следующее: проверка Incase завершается неудачно, вызывается обратный вызов и устанавливается ответ. Но не вернулся. Таким образом, он все еще продолжается, метод переходит к БД и поражает успех / неудачу. Он снова вызывает тот же обратный вызов, в результате чего ответ будет установлен дважды.

Таким образом, решение простое, вам нужно «вернуть» обратный вызов, чтобы метод не продолжал выполняться после возникновения ошибки и, следовательно, один раз установить объект ответа.

  var error = validateRequestDetails("create",queryReq);
    if (error)
        callback(error, null);
        return;
    else
       some code 
       callback(null, success);
хаотичность
источник
1
Спасибо! Это оказалось моей проблемой тоже. Просто сделал ctrl + f и нашел callback(...)без него return;после него, что в итоге вызывало res.send(...)вызов дважды.
15

Этот тип ошибки вы получите при прохождении выписки после отправки ответа.

Например:

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

Это приведет к ошибке, которую вы видите, потому что после отправки ответа следующее res.sendне будет выполнено.

Если вы хотите что-то сделать, вы должны сделать это до отправки ответа.

троянский
источник
Это была моя точная проблема :)
Джоэл Балмер
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и экспресс4.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/

blented
источник
В моем случае также ответ 304. Я использую волокна для обработки. В любом случае ваш ответ очень помогает. спасибо
Dileep Стэнли
Кто-нибудь может объяснить, каковы последствия удаления заголовка etag?
mattwilsn
2
ETag позволяют серверу не отправлять контент, который не изменился. Отключение отключает эту функцию. Запись ETag в Википедии ( en.wikipedia.org/wiki/HTTP_ETag ) содержит более подробное объяснение.
Blented
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();
});
ASHISH RANJAN
источник
2

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

Анкит Манчанда
источник
1

У меня была эта проблема, когда я вкладывал обещания. Обещание внутри обещания вернуло бы 200 на сервер, но тогда выражение catch внешнего обещания вернуло бы 500. Как только я исправил это, проблема исчезла.

rharding
источник
как именно вы это исправили? У меня та же проблема с обещаниями. Я не могу избежать их вложения ... так как мне остановить выполнение в операторе возврата?
Саураб
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; }

KNDheeraj
источник
спасибо за ваше вдохновение, то же самое случилось со мной. Я решил это также с другими условиями.
Амр Абдель Рахман
1

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

Навед Ахмад
источник
1

Я получил аналогичную ошибку при попытке отправить ответ в функции цикла. Простым решением было переместить

res.send («отправить ответ»);

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

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

trustidkid
источник
1

Я просто добавляю ключевое слово возврата как: return res.redirect("/great");и Уолла!

Эммануэль Бенсон
источник
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 () вместо status () .

Нагендер Пратап Чаухан
источник
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сделали трюк.

Майк К
источник
0

В моем случае, в цикле, я поставил res.render()так, возможно, пытались вызвать несколько раз.

Хасан Сефа Озальп
источник
-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 
};
кодировщик
источник