Вызов следующего промежуточного ПО после перенаправления в Express.js

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

В качестве упрощенного примера:

var middlewareExample = function(req, res, next){
  if(req.session){
    refreshSession(req.session, function(err, data){
      if(!err){
        res.redirect('/error');
      }
    });
    next();
  }else{
    res.redirect('/authenticate');
  }
};

Проблема заключается в вызове next после перенаправления, так как он находится вне внутренней функции и условия. Я не уверен, как Express обрабатывает вызовы промежуточного программного обеспечения/маршрута для next или res.redirect, если они происходят до или после друг друга, как показано выше.

Ручное тестирование не выявило странного поведения, как и модуль супертеста. Я хотел бы знать, реагирует ли Express на подобные обстоятельства и как. Кроме того, можно использовать супертест для выявления любого потенциально нежелательного поведения. Кроме того, если можно, я хотел бы услышать, какие подходы другие используют для тестирования промежуточного ПО Node/Express в целом.


person jneander    schedule 14.03.2013    source источник
comment
Что ты пытаешься сделать? и res.redirect('/error'), и next() могут быть вызваны в одном и том же запросе, что испортит весь поток управления.   -  person Jonathan Ong    schedule 14.03.2013
comment
Я получаю Can't set headers after they are sent ошибки, если пытаюсь использовать оба.   -  person robertklep    schedule 14.03.2013
comment
@JonathanOng Я пытаюсь выявить с помощью тестов любую поломку, которая должна происходить, когда обе функции могут вызываться в одном запросе.   -  person jneander    schedule 14.03.2013
comment
@robertklep Есть идеи, где и каким образом эта ошибка может распространяться?   -  person jneander    schedule 14.03.2013
comment
По крайней мере, он появится на консоли, но я не думаю, что вы можете проверить его «извне», потому что это немного спорная ошибка: ответ (в виде перенаправления) уже отправлен на клиент на тот момент.   -  person robertklep    schedule 14.03.2013
comment
После исчерпывающего тестирования я подтвердил, что столкнулся с состоянием гонки. Поскольку для обработки потока ПО промежуточного слоя может потребоваться некоторое время, любое действие, выполняемое с response, например перенаправление, произойдет до того, как обработается оставшееся ПО промежуточного слоя. Я создал фиктивную функцию промежуточного программного обеспечения, которая выполняет res.send(200), и поместил ее после этого примера промежуточного программного обеспечения. При запуске в реальном времени принудительно завершает ответ до того, как перенаправление может быть обработано. Однако в тестах перенаправление все же происходит быстрее. Теперь я должен ввести задержку в тест, чтобы подтвердить состояние гонки.   -  person jneander    schedule 14.03.2013
comment
Вы, наконец, решили это? У меня условия гонки с загрузкой!   -  person qodeninja    schedule 18.11.2013


Ответы (2)


вы отправляете два ответа в одном запросе. next() — это ответ, при условии, что у следующего обработчика тоже есть ответ, как и res.redirect(). То, что вы действительно хотите, это:

var middlewareExample = function(req, res, next){
  if(req.session){
    refreshSession(req.session, next);
  }else{
    res.redirect('/authenticate');
  }
};
person Jonathan Ong    schedule 15.03.2013

Я столкнулся с этой проблемой в приведенном ниже примере.

const redirect = () => (res, resp, next) => {
  if (/* redirect condition met */) {
    return resp.status(302).redirect(`https://example.com/${path_logic()}`);
  } else {
    return next();
  }
}

app.use(redirect());
app.get('*', static('built/project/code'));

Я не смог найти ничего, говорящего о перенаправлениях, не работающих в методе .use. Но, видимо, не разрешено.

Вот мое решение.

const redirect = () => (res, resp, next) => {
  if (/* redirect condition met */) {
    return resp.status(302).redirect(`https://example.com/${path_logic()}`);
  } else {
    return next();
  }
}

app.get('*', [
  redirect(),
  static('built/project/code')
]);

Единственная логическая разница здесь заключается в том, что функция перенаправления работает только в сочетании с обработчиком запросов (.get .post и т. д.), но не .use.

person Lawrence_NT    schedule 29.08.2019