1
votes

Pourquoi ne puis-je pas appeler `next` après qu'une route soit exécutée en express?

J'ai un itinéraire simple comme celui-ci:

// This is just a health check
const endpoint = (req, res, next) => {
  res.json({
    status: 'ok',
  });
  next();
};

router.get('/', endpoint);

J'obtiens Erreur: impossible de définir les en-têtes après leur envoi. depuis express. C'est même si je n'ai aucun autre middleware possible à exécuter ensuite, ou si mon middleware next ne fait littéralement rien et est une fonction vide.

Que me manque-t-il dans la manière dont le middleware et next fonctionne?


0 commentaires

3 Réponses :


0
votes

Je pense que vous y avez répondu dans votre propre question: vous ne pouvez rien faire à une réponse une fois qu'elle a déjà été envoyée. Et si vous y réfléchissez, cela a du sens. Si next est utilisé pour modifier la requête d'une manière ou d'une autre, pourquoi «agirait-il» encore comme si elle «fonctionnait» après que la requête ait déjà été envoyée?

Selon le Documents Express , voici comment ils utilisent next dans un get demande:

app.get('/example/b', function (req, res, next) {
  console.log('the response will be sent by the next function ...')
  next()
}, function (req, res) {
  res.send('Hello from B!')
})


3 commentaires

J'espère prendre quelques données après coup et faire une demande xhr. Est-ce que cela compterait même pour manipuler la réponse? Je comprends que c'est une erreur si j'essaye d'appeler res.send ou quelque chose comme ça à nouveau, mais pas seulement une méthode vide. Mais tu dis que c'est comme ça que c'est censé être, hein?


Ahh! On dirait que vous essayez d'utiliser next d'une manière pour laquelle il n'était pas destiné à être utilisé. Qu'entendez-vous par «prendre des données après coup»?


Cette question fait suite à stackoverflow.com/questions/56243480/... , où une réponse donnait l'impression que je pouvais le faire. Mon désir réel de pouvoir regarder soit: req.path & req.params ou req.route . La deuxième option ne semble pas faisable sans un piratage important. Je prendrais ces données pour définir le nom de transaction approprié dans la nouvelle relique



0
votes

Si vous avez besoin de faire autre chose dans ce point final particulier, la bonne façon serait de le faire avant d'envoyer la réponse. C'est ainsi que fonctionne l'architecture d'Express.

Si vous voulez appliquer la même logique à chaque point de terminaison (cela ressemble à ça, puisque vous voulez vérifier req.path , req.params et / ou req.route ), vous pouvez utiliser un middleware pour écouter l'événement finish d'express:

router.use((req, res, next) => {
  res.on('finish', function() {
    // extra logic here after sending response
  });
  next();
});

const endpoint = (req, res, next) => {
  res.json({
    status: 'ok',
  });
};

router.get('/', endpoint);


4 commentaires

Savez-vous qu'il s'exécutera avant que la connexion ne soit coupée? c'est-à-dire que si je boucle vers un point final, la logique finish se déclenche-t-elle avant que j'obtienne une réponse?


L'intergiciel de finition doit être exécuté après la coupure de la connexion. Par exemple, si vous lancez une erreur dans la ligne extra logic , le client ne recevra aucune erreur.


Ouais, ce serait un problème pour moi étant donné que je veux utiliser ceci pour définir un nom de transaction pour New Relic basé sur le req.route.


Je vois. Le cycle de vie d'une requête dans express se termine par res.json () / res.send () . Vous pouvez transmettre la réponse à un nouveau middleware final à req.response et faire un peu de logique entre les deux.



0
votes

Il peut y avoir quelques problèmes:

Vous avez un gestionnaire 404 à la fin (nous le faisons tous) et vous avez simplement négligé. Par exemple:

function test(x) {
  switch (x) {
    case 'Oranges':
      console.log('Orange juice');
      break;
    case 'Mangoes': // fall through
    case 'Papayas':
      console.log('Pickles');
      break;
    case 'Banana':
      console.log('Milkshake');
      // forgot the break
    case 'Apple':
      console.log('Apple Pie')
      break;
    default:
      console.log('Sorry, no ' + x + '.');
  }
}

test('Banana')

Cela entraînerait une erreur Erreur: Impossible de définir les en-têtes après leur envoi. Parce que votre gestionnaire 404 envoie une réponse .

Ou Vous êtes tombé sur une caractéristique inconnue (Ou simplement, l'un de vos itinéraires ne fonctionne pas comme prévu, peut-être une erreur de conception). Considérez l'itinéraire suivant:

app.get('/path/:id', (req, res, next) => {
  res.json({ message: "Welcome!" });
  next() // <-- calling next middleware
})

app.get('/path/test', (req, res, next) => {
  res.json({ message: "Welcome!" });
})

L'appel de next dans l'itinéraire / path /: id entraînerait une erreur si votre demande le chemin est / path / test (cela suggère en général une meilleure implémentation de routage)

Un moyen simple de comprendre le middleware et le suivant est lié au fonctionnement de l'instruction switch :

app.get('/path', (req, res, next) => {
  res.json({ greet: "Welcome!" })
  next() // <-- calling next middleware
})

// set up a 404 handler at the end
app.use((req, res) => {
  res.status(404).send('Opps! Not Found');
})

Appeler next revient à passer à une instruction switch , exécutez également le cas suivant.

Ainsi, lorsque vous appelez next dans une route et que la demande continue pour correspondre à une autre route (une correspondance involontaire) où vous envoyez réponse, vous vous surprendrez à vous frapper le visage avec l'erreur.


2 commentaires

La 404 était la réponse. J'ai router.get ('*') pour gérer les 404, mais la même différence ici. Superbe capture.


PS: Je vais passer le 404 à un middleware et m'assurer qu'il fonctionne après ce que j'essaye de faire maintenant. Briser ça va arranger les choses