110 votes

Comment envoyer un message d'état http personnalisé dans node / express ?

Mon application node.js est modélisée comme suit express/exemples/mvc app.

Dans une action de contrôleur, je veux renvoyer un statut HTTP 400 avec un message http personnalisé. Par défaut, le message d'état http est "Bad Request" :

HTTP/1.1 400 Bad Request

Mais je veux envoyer

HTTP/1.1 400 Current password does not match

J'ai essayé plusieurs méthodes, mais aucune d'entre elles n'a défini le message d'état http comme étant mon message personnalisé.

Ma fonction actuelle de contrôleur de solution ressemble à cela :

exports.check = function( req, res) {
  if( req.param( 'val')!=='testme') {
    res.writeHead( 400, 'Current password does not match', {'content-type' : 'text/plain'});
    res.end( 'Current value does not match');

    return;
  } 
  // ...
}

Tout fonctionne bien mais ... il semble que ce ne soit pas la bonne façon de faire.

Existe-t-il un meilleur moyen de définir le message d'état http en utilisant express ?

7voto

Bravo Points 59

Lorsque vous utilisez Axios, vous pouvez récupérer le message de réponse personnalisé avec :

Axios.get(“your_url”)
.then(data => {
... do something
}.catch( err => {
console.log(err.response.data) // you want this
})

...après l'avoir paramétré dans Express comme :

res.status(400).send(“your custom message”)

3voto

Sharadh Points 1218

Mon cas d'utilisation est l'envoi d'un message d'erreur JSON personnalisé, puisque j'utilise express pour alimenter mon API REST. Je pense qu'il s'agit d'un scénario assez courant, je me concentrerai donc sur ce point dans ma réponse.

Version courte :

Gestion des erreurs express

Définir un intergiciel de gestion des erreurs comme les autres intergiciels, mais avec quatre arguments au lieu de trois, notamment avec la signature (err, req, res, next). ... Vous définissez l'intergiciel de gestion des erreurs en dernier, après les autres appels à app.use() et routes

app.use(function(err, req, res, next) {
    if (err instanceof JSONError) {
      res.status(err.status).json({
        status: err.status,
        message: err.message
      });
    } else {
      next(err);
    }
  });

Soulever des erreurs à partir de n'importe quel point du code en faisant :

var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);

Version longue

La façon canonique de lancer des erreurs est :

var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)

Par défaut, Express gère cette situation en la présentant comme une réponse HTTP avec un code 404 et un corps constitué de la chaîne de messages accompagnée d'un suivi de pile.

Cela ne me convient pas lorsque j'utilise Express comme serveur REST, par exemple. Je veux que l'erreur soit renvoyée en JSON, et non en HTML. De plus, je ne veux absolument pas que ma trace de pile soit envoyée à mon client.

Je peux envoyer JSON comme réponse en utilisant req.json() par exemple, quelque chose comme req.json({ status: 404, message: 'Uh oh! Can't find something'}) . En option, je peux définir le code d'état en utilisant req.status() . La combinaison des deux :

req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});

Cela fonctionne comme un charme. Cela dit, je trouve que c'est assez lourd à taper à chaque fois que j'ai une erreur, et le code n'est plus auto-documenté comme notre next(err) était. Il ressemble beaucoup trop à la façon dont une réponse JSON normale (c'est-à-dire valide) est envoyée. De plus, toute erreur provoquée par l'approche canonique entraîne toujours une sortie HTML.

C'est là qu'intervient le middleware de gestion des erreurs d'Express. Dans le cadre de mes routes, je définis :

app.use(function(err, req, res, next) {
    console.log('Someone tried to throw an error response');
  });

Je sous-classe également Error dans une classe JSONError personnalisée :

JSONError = function (status, message) {
    Error.prototype.constructor.call(this, status + ': ' + message);
    this.status = status;
    this.message = message;
  };
JSONError.prototype = Object.create(Error);
JSONError.prototype.constructor = JSONError;

Maintenant, quand je veux lancer une erreur dans le code, je le fais :

var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);

Pour revenir au middleware de gestion des erreurs, je le modifie comme suit :

app.use(function(err, req, res, next) {
  if (err instanceof JSONError) {
    res.status(err.status).json({
      status: err.status,
      message: err.message
    });
  } else {
    next(err);
  }
}

La sous-classification de Error en JSONError est importante, car je soupçonne qu'Express fait un instanceof Error sur le premier paramètre passé à un next() pour déterminer si un gestionnaire normal ou un gestionnaire d'erreur doit être invoqué. Je peux supprimer le instanceof JSONError et apporte des modifications mineures pour s'assurer que les erreurs inattendues (comme un crash) renvoient également une réponse JSON.

-1voto

Ted Bigham Points 1572

Si votre but est juste de le réduire à une ligne unique/simple, vous pourriez vous reposer un peu sur les valeurs par défaut...

return res.end(res.writeHead(400, 'Current password does not match'));

-2voto

KNDheeraj Points 319

Eh bien, dans le cas de Restify, nous devrions utiliser sendRaw() méthode

La syntaxe est : res.sendRaw(200, 'Operation was Successful', <some Header Data> or null)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X