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

89

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

В действии контроллера я хочу выдать статус HTTP 400 с помощью настраиваемого HTTP-сообщения. По умолчанию сообщение о состоянии http - «Плохой запрос»:

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 с помощью экспресс?

lgersman
источник
4
Что ж, похоже, это единственный обходной путь. Но я бы не советовал что-то подобное, в спецификации HTTP 1.1 есть стандартизованное описание ошибки по некоторым веским причинам. Я считаю плохой практикой отправлять хорошо известные коды состояния с пользовательскими описаниями, но это зависит от вас.
schaermu 04
Хммм - может, это правда. С другой стороны, я бы предположил, что браузеры просто проверяют код состояния, а не читаемое человеком сообщение о состоянии http. Я подумал, что будет хорошей идеей использовать сообщение о состоянии http для передачи конкретного (т.е. нестандартного) сообщения об ошибке, если оно доступно. Кроме того, это легко понять, используя java-скрипт на стороне клиента (используя jQuery, вы можете выполнить «jqXHR.statusText», чтобы получить ошибку для отображения)
lgersman
4
Дело не в совместимости или потенциальных проблемах с браузером, это просто плохая практика;) если вы хотите, чтобы сообщение об ошибке отображалось, отправьте его как тело, это намеченная цель.
schaermu 04
6
Конкретные описания ошибок не являются частью спецификации. В RCF-2616 конкретно говорится: «Отдельные значения числовых кодов состояния, определенных для HTTP / 1.1, и примерный набор соответствующих фраз-причин, представлены ниже. Перечисленные здесь фразы причин являются только рекомендациями - они МОГУТ быть заменены на местные эквиваленты, не влияя на протокол ".
Тед Бигхэм
Пользовательские фразы причины - это здорово, но (поскольку ваше сообщение - «Текущий пароль не совпадает») похоже, что вам действительно нужен код 401 здесь, и в этом случае вам, вероятно, не нужно менять сообщение.
Codebling

Ответы:

59

Вы можете проверить эту документацию res.send(400, 'Current password does not match') Look express 3.x для получения подробной информации

ОБНОВЛЕНИЕ для Expressjs 4.x

Используйте этот способ (смотрите Документы Express 4.x ):

res.status(400).send('Current password does not match');
// or
res.status(400);
res.send('Current password does not match');
Петр Герасименко
источник
41
к сожалению, это не приведет к установке сообщения о статусе http, но в качестве содержимого тела будет отправлено сообщение «Текущий пароль не совпадает» ...
lgersman
Это устанавливает статус HTTP, но выдает предупреждение, потому что эта подпись метода устарела.
обнуление
1
Этот res.status(400).send('Current password does not match');пример
Tyler Collier
Работает вExpress ^4.16.2
Аджай
103

Ни один из существующих ответов не выполняет то, что изначально запрашивал OP, а именно переопределение фразы-причины по умолчанию (текст, появляющийся сразу после кода состояния), отправляемой Express.

Вы хотите 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
Мамакдон
источник
6
Это правильный способ установить значение, statusMessageотличное от стандартного сообщения, сопоставленного с StatusCode
peteb
4
Вы можете получить собственность в базовом объекте с помощьюres.nativeResponse.statusMessage
sebilasse
@RobertMoskal Протестировано с использованием минимального сервера Express (Express 4.16.1 и Node 12.9.0), и он все еще работает у меня. Проверьте код своего приложения: может что-то еще не так.
mamacdon
Не уверен, почему это не принятый ответ, потому что это определенно решение, по крайней мере, на момент написания этого.
Аарон Саммерс
12

На стороне сервера (промежуточное ПО 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);
    }
});
виноградник
источник
11

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

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);
}
Хантерлофтис
источник
err.status = 400; Я верю, что встречается чаще.
mkmelin
11

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

return res.status(400).json({'error':'User already exists.'});
Манодж Оджа
источник
3

Мой вариант использования - отправка настраиваемого сообщения об ошибке 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');
  });

Я также подклассифицирую 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);
  }
}

Создание подкласса Error в JSONError важно, поскольку я подозреваю, что Express instanceof Errorпроверяет первый параметр, переданный в a, next()чтобы определить, нужно ли вызывать нормальный обработчик или обработчик ошибок. Я могу удалить instanceof JSONErrorпроверку и внести незначительные изменения, чтобы непредвиденные ошибки (например, сбой) также возвращали ответ JSON.

Шарад
источник
2

При использовании 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”)
Браво
источник
0

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

return res.end(res.writeHead(400, 'Current password does not match'));
Тед Бигхэм
источник
-2

Что ж, в случае Restify мы должны использовать sendRaw()метод

Синтаксис: res.sendRaw(200, 'Operation was Successful', <some Header Data> or null)

KNDheeraj
источник