Вопрос по architecture, node.js, javascript, connect – Как заставить промежуточное программное обеспечение NodeJS / connect работать после того, как Responde.end () был вызван?

12

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

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

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

Вы нашли способ сделать это, так как вы задали этот вопрос? Похоже, что нет ответа на эту тему, и я пытаюсь понять, почему команда Connect реализовала вещи так, как они это сделали. conradkdotcom
Ты делаешьres.end("hello") в вашем коде Pavan Kumar Sunkara
да. обработка ответа завершена, ответ готов к передаче. и теперь я хотел бы, например, разместить бревно или что-нибудь почистить. Peter Aron Zentai
Нет, я не нашел ни одного решения, поэтому отказался от функций, требующих этого. Peter Aron Zentai

Ваш Ответ

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

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

И снова: в последнем пункте («постпроцессор») я не касаюсь заголовков, а помещаю все, что было заморожено. Peter Aron Zentai
Учтите, что уровень nodejs / connect заполняется смешанной логикой из различных источников: A) код, представляющий бизнес-логику, и B) код, представляющий инфраструктуру. Таким образом, если два разных человека создают бизнес и инфраструктуру, то здесь не может быть кооперативной / тесно связанной разработки функций. Парень по бизнес-логике должен справляться с такими вещами, как если бы он работал один (не подозревая об инфраструктуре), то коду инфраструктуры нужно то же самое: быть независимым от кода бизнес-уровня. Peter Aron Zentai
25

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

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

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();
});

Функция, прикрепленная к & quot; финишу & quot; событие будет выполнено после того, как ответ записан (это означает, что NodeJS передал заголовок и тело ответа ОС для передачи по сети).

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

это оно ... спасибо! Peter Aron Zentai
@ Боже, хорошая идея. Благодарю.
finish событие не вызывается, если объект ответа уже запустилclose событие - это происходит, когда сокет закрывается до того, как ответ может быть отправлен. Если вы хотите уловить момент, когда цикл запроса / ответа заканчивается (даже когда промежуточное программное обеспечение для обработки ошибок отправляет ответ), возможно, лучше переопределитьend функция ответа:var _end = res.end; res.end = function(){ console.log('the very end of the response'); _end.apply(this, arguments); }
1

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

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

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

Если изменить строку 14, чтобы:

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

Вы увидите, что на самом деле он устанавливает & quot; headersSent & quot; к истине. Поэтому после того, как мы завершили запрос, из кода next () видно, что он выдает ошибку из-за обсуждаемых условий.

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

Похожие вопросы