How to quickly get started with VUE3.0: Learn
Express's error handling middleware can help you handle errors without repeating the same work. Assuming you handle errors directly in the Express route handler:
app.put('/user/:id', async (req, res) => { let user try { user = await User.findOneAndUpdate({ _id: req.params.id }, req.body) } catch (err) { return res.status(err.status || 500).json({ message: err.message }) } return res.json({user}) })
The above code works fine, however, what if there are hundreds of interfaces, then the error handling logic becomes unmaintainable because it is repeated hundreds of times.
Express is divided into different types according to the number of parameters the middleware function takes. The middleware function that accepts 4 parameters is defined as error handling middleware and will only be called when an error occurs.
const app = require('express')() app.get('*', function routeHandler() { // This middleware throws an error and Express will go directly to the next error handler throw new Error('Oops!') }) app.get('*', (req, res, next) => { // This middleware is not an error handler (only 3 parameters), Express will skip it because there is an error in the previous middleware console.log('This will not be printed') }) // Your function must accept 4 parameters in order for Express to treat it as error handling middleware. app.use((err, req, res, next) => { res.status(500).json({ message: err.message }) })
Express will automatically handle synchronization errors for you, such as routeHandler()
method above. But Express doesn't handle asynchronous errors. If an asynchronous error occurs, next()
needs to be called.
const app = require('express')() app.get('*', (req, res, next) => { // The next() method tells Express to go to the next middleware in the chain. // Express does not handle asynchronous errors, so you need to report errors by calling next(). setImmediate(() => { next(new Error('Oops')) }) }) app.use((err, req, res, next) => { res.status(500).json({ message: err.message }) })
Remember that Express middleware is executed sequentially. You should define error handlers last, after all other middleware. Otherwise, your error handler will not be called:
async/await
Express with async/await cannot catch exceptions from promise
, Express was written before ES6, and there is no good solution for how to handle async/await
it throws.
For example, the following server never successfully sends the HTTP response because the Promise reject
is never handled:
const app = require('express')() app.get('*', (req, res, next) => { // Reporting asynchronous errors must pass next() return new Promise((resolve, reject) => { setImmediate(() => reject(new Error('woops'))) }).catch(next) }) app.use((error, req, res, next) => { console.log('will not print') res.json({ message: error.message }) })We can encapsulate
app.listen(3000)
or use an existing library to capture.
First, we simply encapsulate a function to connect async/await
with Express error handling middleware.
NOTE : Async functions return Promise, so you need to make sure to
catch()
any errors and pass them tonext()
.
function wrapAsync(fn) { return function(req, res, next) { fn(req, res, next).catch(next) } } app.get('*', wrapAsync(async (req, res) => { await new Promise(resolve => setTimeout(() => resolve(), 50)) // Async error! throw new Error('woops') }))
Use the third-party library express-async-errors
, a simple ES6 async/await support hack:
require('express-async-errors') app.get('*', async (req, res, next) => { await new Promise((resolve) => setTimeout(() => resolve(), 50)) throw new Error('woops') })
the Express error handling middleware allows you to handle errors in a way that maximizes separation of concerns. You don't need to handle errors in your business logic, not even try/catch
if using async/await
. These errors will appear in your error handler, which can then decide how to respond to the request. Make sure to take advantage of this powerful feature in your next Express app!