Kesalahan dalam Menangani Express

Ketika saya pertama kali mulai bekerja dengan Express dan mencoba mencari cara untuk menangani kesalahan, saya mengalami kesulitan. Ada perasaan bahwa tidak ada yang menulis tentang apa yang saya butuhkan. Akibatnya, saya harus mencari jawaban atas pertanyaan saya sendiri. Hari ini saya ingin memberi tahu semua yang saya tahu tentang penanganan kesalahan dalam aplikasi Express. Mari kita mulai dengan kesalahan sinkron.



Penanganan Kesalahan Sinkron


Jika Anda perlu menangani kesalahan sinkron, maka Anda bisa, pertama-tama, menggunakan pernyataan throw , throw kesalahan seperti itu di penangan permintaan Express. Harap dicatat bahwa penangan permintaan juga disebut "pengendali", tapi saya lebih suka menggunakan istilah "penangan permintaan" karena menurut saya lebih jelas.

Begini tampilannya:

 app.post('/testing', (req, res) => {  throw new Error('Something broke! ') }) 

Kesalahan semacam itu dapat ditangkap menggunakan penangan kesalahan Express. Jika Anda belum menulis penangan kesalahan Anda sendiri (kami akan berbicara lebih banyak tentang ini di bawah), maka Express akan menangani kesalahan menggunakan penangan default.

Inilah yang dilakukan penangan kesalahan Express standar:

  1. Atur kode status respons HTTP ke 500.
  2. Mengirim respons teks ke entitas yang mengeksekusi permintaan.
  3. Mencatat respons teks ke konsol.


Pesan kesalahan ditampilkan di konsol

Penanganan Kesalahan Asinkron


Untuk menangani kesalahan asinkron, Anda perlu mengirim kesalahan ke penangan kesalahan Express melalui argumen next :

 app.post('/testing', async (req, res, next) => {  return next(new Error('Something broke again! ')) }) 

Inilah yang sampai ke konsol saat mencatat kesalahan ini.


Pesan kesalahan ditampilkan di konsol

Jika Anda menggunakan konstruk async / wait dalam aplikasi Express, maka Anda perlu menggunakan fungsi wrapper seperti express-async-handler . Ini memungkinkan Anda untuk menulis kode asinkron tanpa blok coba / tangkap . Baca lebih lanjut tentang async / tunggu di Express di sini .

 const asyncHandler = require('express-async-handler') app.post('/testing', asyncHandler(async (req, res, next) => {  //  - })) 

Setelah penangan permintaan dibungkus express-async-handler , Anda bisa, seperti dijelaskan di atas, melempar kesalahan menggunakan pernyataan throw . Kesalahan ini akan pergi ke penangan kesalahan Express.

 app.post('/testing', asyncHandler(async (req, res, next) => {  throw new Error('Something broke yet again! ') })) 


Pesan kesalahan ditampilkan di konsol

Menulis Handler Kesalahan Anda Sendiri


Penangan kesalahan ekspres mengambil 4 argumen:

  1. kesalahan
  2. req
  3. res
  4. selanjutnya

Anda perlu menempatkan mereka setelah penangan dan rute menengah.

 app.use(/*...*/) app.get(/*...*/) app.post(/*...*/) app.put(/*...*/) app.delete(/*...*/) //           app.use((error, req, res, next) => { /* ... */ }) 

Jika Anda membuat penangan kesalahan sendiri, Express akan berhenti menggunakan penangan kesalahan standar. Untuk menangani kesalahan, Anda perlu membuat respons untuk aplikasi front-end yang membahas titik akhir di mana kesalahan terjadi. Ini berarti bahwa Anda perlu melakukan hal berikut:

  1. Buat dan kirim kode status respons yang sesuai.
  2. Bentuk dan kirim jawaban yang sesuai.

Kode status mana yang sesuai dalam setiap kasus tergantung pada apa yang sebenarnya terjadi. Berikut adalah daftar kesalahan umum yang harus Anda siap tangani:

  1. Kesalahan 400 Bad Request . Digunakan dalam dua situasi. Pertama, ketika pengguna tidak memasukkan bidang yang diperlukan dalam permintaan (misalnya, bidang dengan informasi kartu kredit tidak diisi dalam formulir pembayaran yang dikirim). Kedua, ketika permintaan berisi data yang salah (misalnya, memasukkan kata sandi yang berbeda di bidang kata sandi dan di bidang konfirmasi kata sandi).
  2. Kesalahan 401 Unauthorized . Kode status respons ini diterapkan jika pengguna memasukkan kredensial yang salah (seperti nama pengguna, alamat email, atau kata sandi).
  3. Kesalahan 403 Forbidden . Digunakan saat pengguna tidak diizinkan mengakses titik akhir.
  4. Kesalahan 404 Not Found . Ini digunakan dalam kasus-kasus di mana titik akhir tidak dapat dideteksi.
  5. Kesalahan 500 Internal Server Error Galat 500 Internal Server Error . Itu diterapkan ketika permintaan yang dikirim oleh front-end dibentuk dengan benar, tetapi beberapa kesalahan terjadi di back-end.

Setelah kode status respons yang sesuai ditentukan, kode itu harus ditetapkan menggunakan res.status :

 app.use((error, req, res, next) => {  // ,         res.status(400)  res.json(/* ... */) }) 

Kode status respons harus sesuai dengan pesan kesalahan. Untuk melakukan ini, kirim kode status beserta kesalahannya.

Cara termudah untuk melakukan ini adalah dengan paket http-error . Ini memungkinkan pengiriman tiga informasi yang salah:

  1. Kode status respons.
  2. Pesan terkait dengan kesalahan.
  3. Setiap data yang perlu dikirim (ini opsional).

Berikut ini cara menginstal paket http-errors :

 npm install http-errors --save 

Berikut cara menggunakan paket ini:

 const createError = require('http-errors') //   throw createError(status, message, properties) 

Pertimbangkan contoh yang akan memungkinkan Anda untuk memahami semua ini dengan benar.

Bayangkan kami sedang mencari pengguna di alamat emailnya. Tetapi pengguna ini tidak dapat ditemukan. Akibatnya, kami memutuskan untuk mengirim User not found kesalahan dalam menanggapi permintaan yang sesuai, memberi tahu penelepon bahwa pengguna tidak ditemukan.

Inilah yang perlu kita lakukan saat membuat kesalahan:

  1. Setel kode status respons ke 400 Bad Request (setelah semua, pengguna memasukkan data yang salah). Ini akan menjadi parameter pertama kami.
  2. Kirim pesan ke pemanggil seperti User not found . Ini akan menjadi parameter kedua.

 app.put('/testing', asyncHandler(async (req, res) => {  const { email } = req.body  const user = await User.findOne({ email })  //     -    if (!user) throw createError(400, `User '${email}' not found`) })) 

Anda bisa mendapatkan kode status menggunakan konstruk error.status , dan pesan kesalahan menggunakan error.message :

 //   app.use((error, req, res, next) => {  console.log('Error status: ', error.status)  console.log('Message: ', error.message) }) 


Hasil kesalahan logging di konsol

Kemudian negara respons diatur menggunakan res.status , dan pesan ditulis ke res.json :

 app.use((error, req, res, next) => {  //      res.status(error.status)  //    res.json({ message: error.message }) }) 

Secara pribadi, saya lebih suka mengirim kode status, pesan, dan hasil jejak stack dalam tanggapan seperti itu. Ini membuat proses debug lebih mudah.

 app.use((error, req, res, next) => {  //      res.status(error.status)  //    res.json({    status: error.status,    message: error.message,    stack: error.stack  }) }) 

▍ Kode status respons default


Jika sumber kesalahan bukan createError , maka tidak akan memiliki properti status . Berikut adalah contoh di mana upaya dilakukan untuk membaca file yang tidak ada menggunakan fs.readFile :

 const fs = require('fs') const util = require('util') //  readFile  ,  ,  async/await-. //     : https://zellwk.com/blog/callbacks-to-promises const readFilePromise = util.promisify(fs.readFile) app.get('/testing', asyncHandler(async (req, res, next) => {  const data = await readFilePromise('some-file') }) 

Objek kesalahan seperti itu tidak akan memiliki properti status :

 app.use((error, req, res, next) => {  console.log('Error status: ', error.status)  console.log('Message: ', error.message) }) 


Hasil kesalahan logging di konsol

Dalam kasus seperti itu, Anda dapat mengatur kode kesalahan default. Yaitu, kita berbicara tentang 500 Internal Server Error :

 app.use((error, req, res, next) => {  res.status(error.status || 500)  res.json({    status: error.status,    message: error.message,    stack: error.stack  }) }) 

▍Mengganti kode status kesalahan


Misalkan kita akan membaca file tertentu menggunakan data yang disediakan oleh pengguna. Jika file seperti itu tidak ada, itu berarti bahwa kita perlu memberikan kesalahan 400 Bad Request . Bagaimanapun, server tidak dapat ditemukan karena file tidak dapat ditemukan.

Dalam hal ini, Anda perlu menggunakan konstruksi coba / tangkap untuk menangkap kesalahan asli. Maka Anda perlu membuat ulang objek kesalahan menggunakan createError :

 app.get('/testing', asyncHandler(async (req, res, next) => {  try {    const { file } = req.body    const contents = await readFilePromise(path.join(__dirname, file))  } catch (error) {    throw createError(400, `File ${file} does not exist`)  } }) 

▍ 404 penanganan kesalahan


Jika permintaan melewati semua penangan menengah dan rute, tetapi tidak diproses, ini berarti bahwa titik akhir yang sesuai dengan permintaan tersebut tidak ditemukan.

Untuk menangani 404 Not Found kesalahan, Anda perlu menambahkan, antara rute dan penangan kesalahan, penangan tambahan. Beginilah bentuk penciptaan objek galat 404:

 //  ... // ... app.use((req, res, next) => {  next(createError(404)) }) //  ... 


Detail Kesalahan

▍ catatan kesalahan ERR_HTTP_HEADERS_SENT


Jangan panik jika Anda melihat pesan kesalahan ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client . Itu muncul karena dalam penangan yang sama metode yang mengatur header respons berulang kali disebut. Berikut adalah metode yang memanggil untuk mengatur tajuk respons secara otomatis:

  1. kirim ulang
  2. res.json
  3. kirim ulang
  4. res.sendFile
  5. res.sendStatus
  6. kirim ulang
  7. res.redirect

Jadi, misalnya, jika Anda memanggil metode res.render dan res.json di penangan respons yang sama, Anda akan mendapatkan kesalahan ERR_HTTP_HEADERS_SENT :

 app.get('/testing', (req, res) => {  res.render('new-page')  res.json({ message: 'Β―\_(ツ)_/Β―' }) }) 

Akibatnya, jika Anda menemukan kesalahan ini, hati-hati periksa kode penangan respons dan pastikan bahwa tidak ada situasi di mana beberapa metode yang dijelaskan di atas dipanggil.

▍ Penanganan Kesalahan dan Streaming Data


Jika terjadi kesalahan saat mengalirkan respons ke frontend, maka Anda mungkin mengalami kesalahan yang sama ERR_HTTP_HEADERS_SENT .

Dalam hal ini, penanganan kesalahan harus diteruskan ke penangan standar. Pawang seperti itu akan mengirim kesalahan dan secara otomatis menutup koneksi.

 app.use((error, req, res, next) => {  //       ,        if (res.headersSent) {    return next(error)  }  //     }) 

Ringkasan


Hari ini saya memberi tahu Anda semua yang saya ketahui tentang penanganan kesalahan di Express. Saya harap ini membantu Anda menulis aplikasi Express yang lebih andal.

Pembaca yang budiman! Bagaimana Anda menangani kesalahan dalam proyek Node.js Anda?


Source: https://habr.com/ru/post/id476290/


All Articles