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?
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
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');
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);
}
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);
}
});
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.
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);
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.
Vous pouvez l'utiliser comme ça
return res.status(400).json({'error':'User already exists.'});
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'));
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)