web-dev-qa-db-fra.com

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

Mon application node.js est modélisée comme l'application express/examples/mvc

Dans une action du contrôleur, je souhaite cracher 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é de différentes manières mais aucune d'elles n'a défini le message d'état http à mon message personnalisé.

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

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 le faire. 

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

66
lgersman

Aucune des réponses existantes n'accomplit ce que l'OP avait demandé à l'origine, à savoir remplacer le paramètre par défaut Reason-Phrase (le texte apparaissant immédiatement après le code d'état) envoyé par Express.

Ce que vous voulez, c'est res.statusMessage. Cela ne fait pas partie d'Express, c'est une propriété de l'objet http.Response sous-jacent dans Node.js 0.11+.

Vous pouvez l'utiliser comme ceci (testé dans Express 4.x):

function(req, res) {
    res.statusMessage = "Current password does not match";
    res.status(400).end();
}

Ensuite, utilisez curl pour vérifier que cela fonctionne:

$ curl -i -s http://localhost:3100/
HTTP/1.1 400 Current password does not match
X-Powered-By: Express
Date: Fri, 08 Apr 2016 19:04:35 GMT
Connection: keep-alive
Content-Length: 0
62
mamacdon

Vous pouvez vérifier ceci res.send(400, 'Current password does not match') Look docs 3.x express pour les détails

UPDATE pour Expressjs 4.x

Utilisez cette façon (look docs 4.x express ):

res.status(400).send('Current password does not match');
// or
res.status(400);
res.send('Current password does not match');
50
Peter Gerasimenko

Une manière élégante de gérer les erreurs personnalisées de ce type dans express est la suivante:

function errorHandler(err, req, res, next) {
  var code = err.code;
  var message = err.message;
  res.writeHead(code, message, {'content-type' : 'text/plain'});
  res.end(message);
}

(vous pouvez aussi utiliser express 'intégré express.errorHandler pour cela)

Puis dans votre middleware, avant vos routes:

app.use(errorHandler);

Ensuite, à l'endroit où vous souhaitez créer l'erreur "Le mot de passe actuel ne correspond pas":

function checkPassword(req, res, next) {
  // check password, fails:
  var err = new Error('Current password does not match');
  err.code = 400;
  // forward control on to the next registered error handler:
  return next(err);
}
11
hunterloftis

Côté serveur (middleware Express):

if(err) return res.status(500).end('User already exists.');

Poignée côté client

Angulaire: -

$http().....
.error(function(data, status) {
  console.error('Repos error', status, data);//"Repos error" 500 "User already exists."
});

jQuery: -

$.ajax({
    type: "post",
    url: url,
    success: function (data, text) {
    },
    error: function (request, status, error) {
        alert(request.responseText);
    }
});
8
vineet

Mon cas d'utilisation envoie un message d'erreur JSON personnalisé, car j'utilise express pour activer mon API REST. Je pense que c'est un scénario assez courant, donc je vais me concentrer sur cela dans ma réponse.

Version courte:

Express Error Handling

Définissez le middleware de gestion des erreurs comme un autre middleware, sauf avec quatre arguments au lieu de trois, en particulier avec la signature (err, req, res, next). ... Vous définissez le middleware de traitement des erreurs en dernier, après 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);
    }
  });

Relevez les erreurs 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 manière canonique de jeter des erreurs est:

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

Par défaut, Express gère cela en le conditionnant proprement comme une réponse HTTP avec le code 404 et un corps constitué de la chaîne de message ajoutée à une trace de pile.

Cela ne fonctionne pas pour moi lorsque j'utilise Express en tant que serveur REST, par exemple. Je veux que l'erreur soit renvoyée en JSON, pas en HTML. Je ne veux surtout pas non plus que ma trace de pile soit transférée à mon client.

Je peux envoyer une réponse JSON à l'aide de req.json(), par exemple. quelque chose comme req.json({ status: 404, message: 'Uh oh! Can't find something'}). Je peux éventuellement définir le code d'état à l'aide de req.status(). Combinant les deux:

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

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

C'est ici qu'intervient le middleware de gestion des erreurs d'Express. Dans le cadre de mes itinéraires, 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 jeter une erreur dans le code, je fais:

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

Pour revenir au middleware de gestion d'erreur personnalisé, 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);
  }
}

Il est important de sous-classer les erreurs dans JSONError, car je soupçonne qu'Express effectue une vérification instanceof Error sur le premier paramètre transmis à une next() afin de déterminer si un gestionnaire normal ou un gestionnaire d'erreur doit être appelé. Je peux supprimer la vérification instanceof JSONError et apporter des modifications mineures pour garantir que des erreurs inattendues (telles qu'un blocage) renvoient également une réponse JSON.

3
Sharadh

Vous pouvez l'utiliser comme ça

return res.status(400).json({'error':'User already exists.'});
3
Manoj Ojha

Si votre objectif est simplement de le réduire à une seule ligne, vous pouvez vous fier un peu aux valeurs par défaut ...

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

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

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

0
KNDheeraj