Як надіслати власне повідомлення про статус 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 за допомогою express?


4
Що ж, це, здається, єдине обхідне рішення. Але я б не радив щось подібне, специфікація HTTP 1.1 має опис помилок, стандартизований з якихось вагомих причин. Я вважаю поганою практикою надсилати відомі коди стану зі спеціальними описами, але це залежить від вас.
schaermu

Мда, можливо, це правда. З іншого боку, я вважаю, що браузери просто перевіряють код стану, а не зручне для читання повідомлення про статус http. Я вважаю, що є гарною ідеєю використовувати повідомлення про статус http для перенесення конкретного (тобто не за замовчуванням) повідомлення про помилку, якщо воно доступне. Плюс до того, що його легко схопити, використовуючи скрипт Java на стороні клієнта (використовуючи jQuery, ви можете зробити "jqXHR.statusText", щоб отримати помилку для цілей відображення)
lgersman

4
Справа не в сумісності чи потенційних проблемах з браузером, це просто погана практика;) якщо ви хочете для відображення повідомлення про помилку, надішліть його як основний текст, це пряма мета.
schaermu

6
Конкретні описи помилок не є частиною специфікації. RCF-2616 конкретно зазначає: "Індивідуальні значення числових кодів стану, визначених для HTTP / 1.1, і приклад набору відповідних причин-фраз, представлені нижче. Перелічені тут фрази є лише рекомендаціями - їх МОЖЕ замінити на місцеві еквіваленти, не впливаючи на протокол. "
Тед Бігхем,

Фрази з власною причиною чудові, але (оскільки ваше повідомлення "Поточний пароль не збігається"), здається, ви насправді бажаєте тут код 401, і в цьому випадку вам, можливо, не потрібно змінювати повідомлення.
Codebling

Відповіді:


59

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

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

Скористайтеся цим способом (шукайте експрес-документи 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');Приклад працює для мене кур'єрського 4.
Тайлер Collier

Працює вExpress ^4.16.2
Аджай

103

Жодна з існуючих відповідей не виконує того, про що спочатку просив ОП, тобто замінити стандартну фразу-причину (текст, що з’являється відразу після коду стану), надіслану 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щось інше, ніж стандартне повідомлення, яке відображається у коді стану
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, оскільки я використовую express для живлення мого 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перевірку першого параметра, переданого в 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.