普通middleware
const express = require('express')
const app = express()
const port = 3000
app.use('/normal', (req, res) => res.send('Hello World!'))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
文艺middleware (async)
const express = require('express')
const app = express()
const port = 3000
app.use('/art', async (req, res) => {
await new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
})
res.send('Bonjour le monde!')
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
万一middleware里报错了怎么办
增加一个4参数的中间件作为error handler,当然express也有一个默认的handler
const express = require('express')
const app = express()
const port = 3000
app.use('/normal', (req, res) => res.send('Hello World!'))
app.use('/normal-error', (req, res, next) => {
throw new Error('some error')
})
app.use((err, req, res, next) => res.send('error detected: ' + err.message))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
async middleware里的报错也这么处理?
答案是No
const express = require('express')
const app = express()
const port = 3000
app.use('/art', async (req, res) => {
await new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
})
res.send('Bonjour le monde!')
})
app.use('/2b-error-1', async (req, res) => {
await new Promise((resolve, reject) => {
setTimeout(() => reject('another error 1'), 1000)
})
})
app.use('/2b-error-2', async (req, res) => {
await Promise.resolve().then(() => {
throw new Error('another error 2')
})
})
app.use((err, req, res, next) => res.send('error detected: ' + err.message))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
如果只这样写的话,浏览器里不会有任何返回,而你会在终端里得到下面的报错:
正确处理async middleware里的报错
const express = require('express')
const app = express()
const port = 3000
app.use('/art', async (req, res) => {
await new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
})
res.send('Bonjour le monde!')
})
app.use('/art-error-1', async (req, res, next) => {
try {
await new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('another error 1')), 1000)
})
} catch (e) {
next(e)
}
})
app.use('/art-error-2', async (req, res, next) => {
await Promise.resolve().then(() => {
throw new Error('another error 2')
}).catch(next)
})
app.use((err, req, res, next) => res.send('error detected: ' + err.message))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
处理的办法就是catch住异步操作中可能会抛出的错误,这里其实没有新的内容,在express的文档里已经说了必须捕获异步操作中的错误:
You must catch errors that occur in asynchronous code invoked by route handlers or middleware and pass them to Express for processing.
每个异步操作都如此try/catch,太麻烦了
解决办法是写一个高阶函数asyncMiddleware
,在这个函数里面给传进来的middleware自动加上catch方法。
const express = require('express')
const app = express()
const port = 3000
app.use('/art', async (req, res) => {
await new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
})
res.send('Bonjour le monde!')
})
// 重点
function asyncMiddleware(fn) {
return (req, res, next) => fn(req, res, next).catch(next)
}
app.use('/art-error-1', asyncMiddleware(async (req, res, next) => {
await new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('another error 1')), 1000)
})
}))
app.use('/art-error-2', asyncMiddleware(async (req, res, next) => {
await Promise.resolve().then(() => {
throw new Error('another error 2')
})
}))
app.use((err, req, res, next) => res.send('error detected: ' + err.message))
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
如果不确定参数是否一定为async function,可以使用Promise.resolve(fn(req, res, next))