Как выполнить выполнение промежуточного программного обеспечения 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 Я получил часть, которая каким-то образом подразумевает, что если заголовки уже отправлены, то выполнение обработчика маршрута должно инициализировать заголовки ответов.

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

Ответ 1

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

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

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 передал заголовок ответа и тело в ОС для сетевой передачи).

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

Ответ 2

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

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

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

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() не используется для использования, которое вы используете.

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

Ответ 3

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

Итак, просмотрев 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. Поэтому после того, как мы закончили запрос, вы можете увидеть из следующего() кода, что он выдает ошибку из-за обсуждаемых условий.