【问题标题】:How to send a custom http status message in node / express?如何在节点/快递中发送自定义 http 状态消息?
【发布时间】:2012-12-18 17:25:27
【问题描述】:

我的 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 状态消息?

【问题讨论】:

  • 好吧,这似乎是唯一的解决方法。但我不会建议这样的事情,HTTP 1.1 规范出于某些充分的理由将其错误描述标准化。我认为发送带有自定义描述的知名状态代码是不好的做法,但这取决于您。
  • 嗯——也许那是真的。另一方面,我会假设浏览器只检查状态代码而不是人类可读的 http 状态消息。我认为使用 http 状态消息来传输具体(即非默认)错误消息(如果可用)是个好主意。另外,使用客户端 java 脚本很容易抓住它(使用 jQuery,您可以执行“jqXHR.statusText”来获取错误以用于显示目的)
  • 这与兼容性或潜在的浏览器问题无关,这只是一种不好的做法;)如果您想要显示错误消息,请将其作为正文发送,这是预期目的。
  • 具体的错误描述不是规范的一部分。 RCF-2616 明确指出:“为 HTTP/1.1 定义的数字状态代码的各个值,以及一组相应的原因短语的示例,如下所示。此处列出的原因短语只是建议——它们可以替换为不影响协议的本地等价物。”
  • 自定义原因短语很棒,但是(因为您的消息是“当前密码不匹配”)听起来您实际上想要代码 401,在这种情况下您可能不需要更改消息。

标签: node.js express


【解决方案1】:

现有的答案都不能满足 OP 最初的要求,即覆盖 Express 发送的默认 Reason-Phrase(紧跟在状态码之后的文本)。

你想要的是res.statusMessage。这不是 Express 的一部分,它是 Node.js 0.11+ 中底层 http.Response 对象的属性。

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

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

然后使用curl 验证它是否有效:

$ 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

【讨论】:

  • 这是将statusMessage 设置为映射到StatusCode 的标准消息以外的其他内容的正确方法
  • 可以通过res.nativeResponse.statusMessage获取底层对象中的属性
  • @RobertMoskal 使用最小的 Express 服务器(Express 4.16.1 和 Node 12.9.0)进行了测试,它仍然适用于我。检查您的应用程序代码:可能还有其他问题。
  • 不知道为什么这不是公认的答案,因为它绝对是解决方案,至少在我写这篇文章的时候。
  • 这应该适用于 HTTP1.1,而不是 HTTP2:nodejs.org/dist/latest-v15.x/docs/api/…
【解决方案2】:

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

Expressjs 4.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');

【讨论】:

  • 不幸的是,这不会设置 http 状态消息,但会发送“当前密码不匹配”作为正文内容...
  • 这确实设置了 HTTP 状态,但会引发警告,因为此方法签名已被弃用。
  • res.status(400).send('Current password does not match'); 示例适用于 Express 4。
  • Express ^4.16.2工作
  • 它有效,但它是在正文中发送的,而不是作为“原因短语”...请参阅下面@mamacdon 的答案,唯一正确的人
【解决方案3】:

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

然后你要在哪里创建错误'当前密码不匹配':

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

【讨论】:

  • err.status = 400;我相信更常见。
【解决方案4】:

你可以这样使用它

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

【讨论】:

  • 这不是 OP 要求的; @mamacdon 是唯一做对的人
【解决方案5】:

在服务器端(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 要求的; @mamacdon 是唯一做对的人
【解决方案6】:

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

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

...在 Express 中设置为:

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

【讨论】:

  • 这么简单,你上面的人为什么要把事情搞得这么复杂。
  • 因为这不是 OP 要求的,@iqbal125....mamacdon 是唯一一个做对的人
【解决方案7】:

我的用例是发送自定义 JSON 错误消息,因为我使用 express 来支持我的 REST API。我认为这是一个相当普遍的情况,所以我会在回答中重点关注这一点。

短版:

Express Error Handling

像其他中间件一样定义错误处理中间件,除了 四个参数而不是三个参数,特别是带有签名(错误, 请求,资源,下一个)。 ...您最后定义错误处理中间件,之后 其他 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)

默认情况下,Express 通过将其巧妙地打包为带有代码 404 的 HTTP 响应以及由附加堆栈跟踪的消息字符串组成的正文来处理此问题。

例如,当我将 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');
  });

我还将 Error 子类化为自定义 JSONError 类:

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

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

【讨论】:

  • 努力的最高分,但这不是 OP 所要求的。 @mamacdon 是唯一做对的人
【解决方案8】:

如果您的目标只是将其简化为单行/简单行,您可以稍微依赖默认值...

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

【讨论】:

    【解决方案9】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-07
      • 2020-08-18
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 2017-05-09
      • 1970-01-01
      相关资源
      最近更新 更多