Как запустить промежуточное ПО NodeJS/connect после вызова responsee.end()?

Я хотел бы добиться чего-то вроде этого:

var c = require('connect');
var app = c();

app.use("/api", function(req, res, next){
    console.log("request filter 1");
    next();
});

app.use("/api", function(req, res, next){
    console.log("request filter 2");
    next();
});

app.use("/api", function(req, res, next){
   console.log("request handler");
    res.end("hello");
    next();
});

app.use("/api", function(req, res, next){
    console.log("response post processor");
    next();
});
app.listen(3000);

Когда я скручиваюсь для адреса, я получаю исключение для консоли, жалующейся на заголовки, которые нельзя беспокоить после отправки, что достаточно справедливо. Только то, что я не трогаю объект ответа.

/usr/bin/node app2.js
request filter 1
request filter 2
request handler
Error: Can't set headers after they are sent.
    at ServerResponse.OutgoingMessage.setHeader (http.js:644:11)
    at ServerResponse.res.setHeader (/home/zpace/node_modules/connect/lib/patch.js:59:22)
    at next (/home/zpace/node_modules/connect/lib/proto.js:153:13)
    at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:25:5)
    at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
    at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:19:5)
    at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
    at Object.handle (/home/zpace/WebstormProjects/untitled1/app2.js:14:5)
    at next (/home/zpace/node_modules/connect/lib/proto.js:190:15)
    at Function.app.handle (/home/zpace/node_modules/connect/lib/proto.js:198:3)

При отладке уровня NodeJS/Connect я попал в часть, которая каким-то образом подразумевает, что если заголовки уже отправлены, то выполнение обработчика маршрута должно инициализировать заголовки ответов.

Вопрос в том, является ли вышеупомянутое поведение преднамеренным (т. е. выполнение любого кода после того, как обработчик маршрута закончил отправку ответа, является чем-то совершенно невообразимым или это просто ошибка в подключении?


person Peter Aron Zentai    schedule 04.07.2012    source источник
comment
Вы делаете res.end("hello") в своем коде   -  person Pavan Kumar Sunkara    schedule 05.07.2012
comment
да. обработка ответа завершена, ответ готов к передаче. и теперь я хотел бы например разместить журнал или что-то очистить.   -  person Peter Aron Zentai    schedule 05.07.2012
comment
Вы нашли способ сделать это с тех пор, как задали этот вопрос? Кажется, в этой теме нет ответа, и я пытаюсь понять, почему команда Connect реализовала вещи так, как они это сделали.   -  person conradkleinespel    schedule 14.09.2013
comment
Нет, я не нашел никакого решения, поэтому отказался от необходимых функций.   -  person Peter Aron Zentai    schedule 15.09.2013


Ответы (3)


Не уверен, что вы нашли свое решение.

Если вы хотите разработать постпроцессор для цикла запроса, вы можете использовать промежуточное программное обеспечение, которое прослушивает событие «завершение» в объекте ответа. Как это:

app.use(function(req, res, next){
  res.on('finish', function(){
    console.log("Finished " + res.headersSent); // for example
    console.log("Finished " + res.statusCode);  // for example
    // Do whatever you want
  });
  next();
});

Функция, прикрепленная к событию «finish», будет выполнена после того, как ответ будет записан (что означает, что NodeJS передал заголовок и тело ответа ОС для передачи по сети).

Я думаю, это должно быть то, что вы хотите.

person Weihong Diao    schedule 18.02.2014
comment
Событие finish не запускается, если объект ответа уже запустил событие close — это происходит, когда сокет закрывается до отправки ответа. Если вы хотите поймать момент, когда заканчивается цикл запроса/ответа (даже когда промежуточное ПО для обработки ошибок отправляет ответ), возможно, лучше переопределить функцию end ответа: var _end = res.end; res.end = function(){ console.log('the very end of the response'); _end.apply(this, arguments); } - person godness; 27.12.2016

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

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

Поэтому не заканчивайте ответ, пока не будет вызван постпроцессор.

var isEnd;

app.use("/*", function(req, res, next){
  isEnd = false;
})

app.use("/api", function(req, res, next){
   console.log("request handler");
    res.write("hello");
    isEnd = true;
    next();
});

app.use("/api", function(req, res, next){
    console.log("response post processor");
    if(isEnd) {
        res.end();
    }
    else next();
});

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

На мой взгляд, очень плохо, что вы вызываете next() после завершения ответа. Если вам нужен постпроцессор, зачем вы это делаете в фильтре запросов (или что это такое). Вызовите функцию, но не next()

Может быть, это:

app.use("/api", function(req, res, next){
   console.log("request handler");
    res.end("hello");
    setTimeout(function(){(postProcessor(req)},0);
});

function postProcessor(req) {
//doing post process stuff.
//response not needed because already ended.
}

Или это:

app.use("/api", function(req, res, next){
   console.log("request handler");
    res.writed("hello");
    setTimeout(function(){(postProcessor(req)},0);
    // u cant res.end here because setTimeout. 
    //If you dont use setTimeout you can use res.end here, but not bot function.
});

function postProcessor(req, res) {
//doing post process stuff.
res.end();
}

next() не для того использования, что вы используете.

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

person Gergely Fehérvári    schedule 04.07.2012
comment
Учтите, что уровень nodejs/connect заполняется смешанной логикой из разных источников: A) код, представляющий бизнес-логику, и B) код, представляющий инфраструктуру. Таким образом, если два разных человека создают части бизнеса и инфраструктуры, здесь не может быть совместной/сильно связанной разработки функций. Специалист по бизнес-логике должен справляться с вещами так, как если бы он работал в одиночку (не зная об инфраструктуре), код инфраструктуры нуждается в том же: быть агностиком в отношении кода бизнес-уровня. - person Peter Aron Zentai; 06.07.2012
comment
И еще: в последней функции (постпроцессор) я не трогаю заголовки, тела всего, что было заморожено. - person Peter Aron Zentai; 06.07.2012

Какой отличный вопрос, чтобы попробовать потренироваться с утренним кофе!

Итак, просматривая proto.js, если вы посмотрите вниз на строку 102, которая является app.handle, которая является кодом обработчика для стека промежуточного программного обеспечения, вы увидите, как работает next().

Там, где вызывается функция next(), вы можете видеть, что она проверяет, является ли значение res.headerSent истинным, и если да, то выдает ошибку.

Если изменить строку 14 на:

app.use("/api", function(req, res, next){
   console.log("request handler");
    res.end("hello");
    console.log(res);
    next();
});

Вы увидите, что на самом деле он устанавливает "headersSent" в true. Итак, после того, как мы завершили запрос, вы можете видеть из кода next(), что он выдает ошибку из-за обсуждаемых условий.

person Menztrual    schedule 04.07.2012
comment
да, но отправка запроса не обязательно означает, что мы закончили цикл запроса. ИМХО, это всего лишь один из возможных подходов. - person Peter Aron Zentai; 06.07.2012