Bagaimana cara mengirim pesan status http khusus di node / express?

90

Aplikasi node.js saya dimodelkan seperti aplikasi express / example / mvc .

Dalam aksi kontroler saya ingin mengeluarkan status HTTP 400 dengan pesan http khusus. Secara default, pesan status http adalah "Permintaan Buruk":

HTTP/1.1 400 Bad Request

Tapi saya ingin mengirim

HTTP/1.1 400 Current password does not match

Saya mencoba berbagai cara tetapi tidak ada yang mengatur pesan status http ke pesan khusus saya.

Fungsi pengontrol solusi saya saat ini terlihat seperti itu:

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

Semuanya bekerja dengan baik tapi ... sepertinya bukan cara yang tepat untuk melakukannya.

Apakah ada cara yang lebih baik untuk menyetel pesan status http menggunakan ekspres?

lgersman
sumber
4
Nah, ini sepertinya satu-satunya solusi. Tetapi saya tidak akan menyarankan sesuatu seperti itu, spesifikasi HTTP 1.1 memiliki deskripsi kesalahannya yang distandarisasi untuk beberapa alasan bagus. Saya pikir itu praktik yang buruk untuk mengirim kode status terkenal dengan deskripsi khusus, tapi itu terserah Anda.
schaermu
Hmmm - mungkin itu benar. Di sisi lain, saya akan menganggap browser hanya memeriksa kode status dan bukan pesan status http yang dapat dibaca manusia. Saya pikir itu adalah ide yang baik menggunakan pesan status http untuk mengangkut pesan kesalahan konkret (yaitu non default) jika tersedia. Selain itu, mudah untuk mengambilnya dengan menggunakan skrip java sisi klien (menggunakan jQuery Anda dapat melakukan "jqXHR.statusText" untuk mendapatkan kesalahan untuk tujuan tampilan)
lgersman
4
Ini bukan tentang kompatibilitas atau potensi masalah browser, ini hanya praktik yang buruk;) jika Anda menginginkan pesan kesalahan untuk ditampilkan, kirimkan sebagai isi, itulah tujuan yang dimaksudkan.
schaermu
6
Deskripsi kesalahan khusus bukan bagian dari spesifikasi. RCF-2616 secara khusus menyatakan: "Nilai individu dari kode status numerik yang ditentukan untuk HTTP / 1.1, dan contoh kumpulan Frasa-Alasan yang sesuai, disajikan di bawah ini. Frasa alasan yang tercantum di sini hanyalah rekomendasi - MUNGKIN diganti dengan lokal yang setara tanpa mempengaruhi protokol. "
Ted Bigham
Frase alasan kustom sangat bagus, tetapi (karena pesan Anda adalah "Sandi saat ini tidak cocok '") sepertinya Anda sebenarnya menginginkan kode 401 di sini, dalam hal ini Anda mungkin tidak perlu mengubah pesan.
Codebling

Jawaban:

60

Anda dapat memeriksa dokumenres.send(400, 'Current password does not match') Look express 3.x ini untuk mengetahui detailnya

UPDATE untuk Expressjs 4.x

Gunakan cara ini (lihat dokumen Express 4.x ):

res.status(400).send('Current password does not match');
// or
res.status(400);
res.send('Current password does not match');
Peter Gerasimenko
sumber
41
sayangnya ini tidak akan menyetel pesan status http tetapi akan mengirim 'Kata sandi saat ini tidak cocok' sebagai konten tubuh ...
lgersman
Ini memang menyetel status HTTP, tetapi melontarkan peringatan karena tanda tangan metode ini sudah tidak digunakan lagi.
nullability
1
The res.status(400).send('Current password does not match');contoh bekerja untuk saya untuk Express 4.
Tyler Collier
Bekerja diExpress ^4.16.2
Ajay
105

Tak satu pun dari jawaban yang ada mencapai apa yang diminta OP pada awalnya, yaitu menimpa Frase-Alasan default (teks yang muncul segera setelah kode status) yang dikirim oleh Express.

Apa yang kamu inginkan adalah res.statusMessage. Ini bukan bagian dari Express, ini adalah properti dari objek http.Response yang mendasari di Node.js 0.11+.

Anda dapat menggunakannya seperti ini (diuji di Express 4.x):

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

Kemudian gunakan curluntuk memverifikasi bahwa itu berfungsi:

$ 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
mamacdon
sumber
6
Ini adalah cara yang benar untuk menyetel statusMessageke sesuatu selain pesan standar yang dipetakan ke StatusCode
peteb
4
Anda bisa mendapatkan properti di objek pokok denganres.nativeResponse.statusMessage
sebilasse
@RobertMoskal Diuji menggunakan server Express minimal (Express 4.16.1 dan Node 12.9.0), dan masih berfungsi untuk saya. Periksa kode aplikasi Anda: mungkin ada yang salah.
mamacdon
Tidak yakin mengapa ini bukan jawaban yang diterima karena ini pasti solusinya, setidaknya pada saat saya menulis ini.
Aaron Summers
1
Ini seharusnya berfungsi untuk HTTP1.1, bukan HTTP2: nodejs.org/dist/latest-v15.x/docs/api/…
Jokesterfr
12

Di sisi server (middleware Express):

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

Tangani di sisi Klien

Sudut: -

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

Satu cara elegan untuk menangani kesalahan khusus seperti ini secara cepat adalah:

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

(Anda juga dapat menggunakan express 'built-in express.errorHandler untuk ini)

Kemudian di middleware Anda, sebelum rute Anda:

app.use(errorHandler);

Lalu di mana Anda ingin membuat kesalahan 'Kata sandi saat ini tidak cocok':

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);
}
hunterloftis
sumber
err.status = 400; lebih umum saya percaya.
mkmelin
11

Anda bisa menggunakannya seperti ini

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

Kasus penggunaan saya mengirimkan pesan kesalahan JSON khusus, karena saya menggunakan express untuk memberdayakan REST API saya. Saya pikir ini adalah skenario yang cukup umum, jadi fokuslah pada jawaban saya.

Versi pendek:

Penanganan Kesalahan Ekspres

Definisikan middleware penanganan kesalahan seperti middleware lainnya, kecuali dengan empat argumen, bukan tiga, khususnya dengan tanda tangan (err, req, res, next). ... Anda menentukan penanganan kesalahan middleware terakhir, setelah app.use () lain dan merutekan panggilan

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

Tingkatkan kesalahan dari titik mana pun dalam kode dengan melakukan:

var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);

Versi Panjang

Cara kanonik untuk melempar kesalahan adalah:

var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)

Secara default, Express menangani ini dengan mengemasnya secara rapi sebagai Respons HTTP dengan kode 404, dan isi yang terdiri dari string pesan yang ditambahkan dengan jejak tumpukan.

Ini tidak berfungsi untuk saya ketika saya menggunakan Express sebagai server REST, misalnya. Saya ingin kesalahan dikirim kembali sebagai JSON, bukan sebagai HTML. Saya juga pasti tidak ingin pelacakan tumpukan saya dipindahkan ke klien saya.

Saya dapat mengirim JSON sebagai tanggapan menggunakan req.json(), misalnya. sesuatu seperti req.json({ status: 404, message: 'Uh oh! Can't find something'}). Secara opsional, saya dapat mengatur kode status menggunakan req.status(). Menggabungkan keduanya:

req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});

Ini bekerja seperti pesona. Karena itu, saya merasa cukup sulit untuk mengetik setiap kali saya mengalami kesalahan, dan kodenya tidak lagi mendokumentasikan diri seperti next(err)sebelumnya. Ini terlihat terlalu mirip dengan bagaimana JSON respon normal (yaitu, valid) dikirim. Lebih lanjut, kesalahan apa pun yang dilemparkan oleh pendekatan kanonik masih menghasilkan keluaran HTML.

Di sinilah middleware penanganan kesalahan Express masuk. Sebagai bagian dari rute saya, saya mendefinisikan:

app.use(function(err, req, res, next) {
    console.log('Someone tried to throw an error response');
  });

Saya juga membuat subclass Error menjadi kelas JSONError kustom:

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;

Sekarang, ketika saya ingin menampilkan Error pada kode, saya lakukan:

var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);

Kembali ke middleware penanganan kesalahan khusus, saya memodifikasinya menjadi:

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

Subclassing Error ke JSONError penting, karena saya menduga Express melakukan instanceof Errorpemeriksaan pada parameter pertama yang diteruskan ke a next()untuk menentukan apakah penangan normal atau penangan kesalahan harus dipanggil. Saya dapat menghapus instanceof JSONErrorcentang dan membuat modifikasi kecil untuk memastikan kesalahan tak terduga (seperti crash) juga mengembalikan respons JSON.

Sharadh
sumber
3

Saat menggunakan Axios, Anda dapat mengambil pesan respons kustom dengan:

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

... setelah mengaturnya di Express sebagai:

res.status(400).send(“your custom message”)
Bravo
sumber
sangat sederhana, mengapa orang-orang di atas Anda harus membuat hal-hal jadi rumit.
iqbal125
0

Jika tujuan Anda hanya untuk menguranginya menjadi satu baris / sederhana, Anda dapat mengandalkan sedikit default ...

return res.end(res.writeHead(400, 'Current password does not match'));
Ted Bigham
sumber
-2

Nah dalam kasus Restify kita harus menggunakan sendRaw()metode

Sintaksnya adalah: res.sendRaw(200, 'Operation was Successful', <some Header Data> or null)

KNDheeraj
sumber