Как отправить пользовательское сообщение о статусе http в node/express?

Мое приложение node.js моделируется как приложение express/examples/mvc.

В действии контроллера я хочу выплюнуть статус HTTP 400 с пользовательским сообщением http. По умолчанию сообщение 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;
  } 
  // ...
}

Все работает отлично, но... кажется, это не правильный способ сделать это.

Есть ли лучший способ установить сообщение статуса http с помощью экспресс?

Ответ 1

Вы можете проверить этот res.send(400, 'Current password does not match') Посмотрите Экспресс 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');

Ответ 2

Ни один из существующих ответов не выполняет то, что первоначально запросил ОП, что должно переопределить стандартную Причина-Фраза (текст, появляющийся сразу после кода состояния) Экспресс.

Вы хотите res.statusMessage. Это не часть Express, это свойство базового объекта http.Response в Node.js 0.11 +.

Вы можете использовать его как это (проверено в 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

Ответ 3

Один элегантный способ обработки пользовательских ошибок, подобных этому в выражении:

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

Ответ 4

На стороне сервера (промежуточное ПО Express):

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

Обработка на стороне клиента

Angular: -

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

Ответ 5

Мой прецедент отправляет пользовательское сообщение об ошибке JSON, так как я использую функцию экспресс-доставки для моего REST API. Я думаю, что это довольно распространенный сценарий, поэтому я сосредоточусь на этом в своем ответе.

Краткая версия:

Экспресс-обработка ошибок

Определите промежуточное программное обеспечение для обработки ошибок, такое как другое промежуточное программное обеспечение, за исключением четыре аргумента вместо трех, в частности, с сигнатурой (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)

По умолчанию Express обрабатывает это, аккуратно упаковывая его как HTTP-ответ с кодом 404 и тело, состоящее из строки сообщения, прилагаемой к трассировке стека.

Это не работает для меня, когда я использую Express как сервер REST, например. Я хочу, чтобы ошибка была отправлена ​​как JSON, а не как HTML. Я также определенно не хочу, чтобы моя трассировка стека была перенесена на моего клиента.

Я могу отправить JSON в качестве ответа, используя req.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');
  });

Я также подклассу Ошибка в пользовательский класс 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 выполняет проверку instanceof Error первого параметра, переданного в next(), чтобы определить, должен ли быть вызван нормальный обработчик или обработчик ошибок. Я могу удалить проверку instanceof JSONError и внести незначительные изменения, чтобы гарантировать, что непредвиденные ошибки (например, сбой) также возвращают ответ JSON.

Ответ 6

Вы можете использовать его так:

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

Ответ 7

Если ваша цель - просто свести его к одной/простой строке, вы можете немного по-разному установить значения по умолчанию...

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