Как отправить собственное сообщение о статусе 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 с помощью экспресс?


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


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)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.