如何发送自定义 http 状态消息在节点/快递?

我的 node.js 应用程序的建模类似于 express/examples/mvc应用程序。

在控制器操作中,我希望使用自定义的 HTTP 消息显示 HTTP 400状态。 默认情况下,http 状态消息是“ Bad Request”:

HTTP/1.1 400 Bad Request

但我想送

HTTP/1.1 400 Current password does not match

我尝试了各种方法,但没有一种方法将 http 状态消息设置为我的自定义消息。

我当前的解决方案控制器函数是这样的:

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;
}
// ...
}

一切都很顺利,但是... 这似乎不是正确的方法。

使用 Express 设置 http 状态消息是否有更好的方法?

139001 次浏览

你可以检查这个 res.send(400, 'Current password does not match') 详情请参阅 Express 3.x docs

Expressjs4.x 的更新

这样使用(看 Express 4.x docs) :

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

在 Express 中处理这种自定义错误的一种优雅方法是:

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);
}

(也可以使用 Express’内置的 Express.errorHandler进行此操作)

然后在你的中间件中,在你的路线之前:

app.use(errorHandler);

然后在您想要创建错误“ Current password does not match”的地方:

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);
}

If your goal is just to reduce it to a single/simple line, you could rely on defaults a bit...

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

我的用例正在发送一个自定义的 JSON 错误消息,因为我使用 Express 来支持我的 REST API。我认为这是一个相当普遍的情况,所以将集中在我的答案。

简短版本:

Express Error Handling

与其他中间件一样定义错误处理中间件,但使用 四个参数而不是三个,特别是使用签名(err, Req,res,next) ... 您最后定义错误处理中间件,然后 其他 app.use ()和路由调用

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);
}
});

通过以下操作从代码中的任何一点引发错误:

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

长篇大论

抛出错误的标准方式是:

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

By default, Express handles this by neatly packaging it as a HTTP Response with code 404, and body consisting of the message string appended with a stack trace.

例如,当我使用 Express 作为 REST 服务器时,这对我不起作用。我希望将错误作为 JSON 而不是 HTML 发送回去。我也绝对不希望我的堆栈跟踪移动到我的客户端。

我可以使用 req.json()发送 JSON 作为响应,例如 req.json({ status: 404, message: 'Uh oh! Can't find something'})。可选地,我可以使用 req.status()设置状态代码。将两者结合起来:

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

这招真管用。也就是说,我发现每次出现错误时键入代码是相当麻烦的,而且代码不再像我们的 next(err)那样自我归档。它看起来与发送普通(即有效)响应 JSON 的方式非常相似。此外,规范方法抛出的任何错误仍然会导致 HTML 输出。

这就是 Express 错误处理中间件的用武之地:

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

I also subclass Error into a custom JSONError class:

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;

现在,当我想在代码中抛出一个错误时,我会这样做:

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

回到自定义错误处理中间件,我将其修改为:

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);
}
}

将 Error 子类化为 JSONError 非常重要,因为我怀疑 Express 会对传递给 next()的第一个参数进行 instanceof Error检查,以确定是否必须调用普通处理程序或错误处理程序。我可以删除 instanceof JSONError检查并进行一些小的修改,以确保意外的错误(比如崩溃)也返回 JSON 响应。

在服务器端(Express 中间件) :

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

客户端处理

角度:-

$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);
}
});

现有的答案都没有完成 OP 最初的要求,即覆盖 Express 发送的默认 Reason-Phrase(状态代码之后立即出现的文本)。

你想要的是 res.statusMessage。这不是 Express 的一部分,它是基础 http 的属性。Js 0.11 + 中的响应对象。

你可以这样使用它(在 Express 4.x 中测试过) :

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

Then use curl to verify that it works:

$ 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

你可以像这样使用它

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

在 Restify 的情况下,我们应该使用 sendRaw()方法

语法是: res.sendRaw(200, 'Operation was Successful', <some Header Data> or null)

使用 Axios 时,您可以使用以下方法检索自定义响应消息:

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

在快递设置为:

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