本文节选自 Next.js 利用开发实际
Next.js 没有中间件机制。首先让我简略解释一下什么是中间件,为什么咱们须要中间件。
在 Express/Koa, 咱们能够用中间件进入一个申请的生命周期,一个典型的中间件是一个函数,它承受 req
, res
和 next
参数:
function exampleMiddleware(req, res, next) { if (/** ...*/) { req.foo = 'bar' next() } else { res.statusCode = 403 res.send('forbiddon') }}
这个中间件的模式起源于一个 Node.js Web 框架 connect, 晚期的 Express 也基于 Connect 开发,于是很多框架也兼容了这种模式,所以这种中间件模式咱们通常称为 connect 中间件。
在中间件里,咱们能够:
- 在
req
对象注入一些属性,这些属性能够被下一个中间件或者 controller 获取到。 - 能够通过不执行
next()
来停止申请,同时批改res
的属性从而扭转 response 的状态。
这使得中间件能够很好地使代码在不同的路由之间重用。假如咱们须要在一个路由跟据 cookies 获取用户信息,咱们能够把这个获取用户信息的办法写成中间件,而后把用户信息注入到 req.user
,这样所以应用了这个中间件的路由能够通过 req.user
获得用户信息。而且在中间件中,如果判断用户没有登录,能够停止这个申请,并返回 403.
上面是 Express 编写和应用中间件的例子:
function authMiddleware(req, res, next) { // 假如 cookies 中用 `token` 保留用户信息 if (req.cookies.token) { const user = getUserByToken(req.cookies.token) req.user = user next() } else { // cookies.token 不存在,停止申请并返回 403 res.statusCode = 403 res.send('please sign in first') }}// 不应用这个中间件的路由app.get('/', (req, res) => { res.send('hello world')})// 应用这个中间件的路由app.get('/profile', authMiddleware, (req, res) => { // 能够通过 `req.user` 获得用户信息 res.send(`welcome! ${req.user.name}`)})
如果在 Next.js 要做同样的事,咱们会这么做:
// pages/api/example.tsfunction auth(req, res) { if (req.cookies.token) { const user = getUserByToken(req.cookies.token) return user } else { // 用户未登录 res.status(403) res.send('please sign in first') }}export default (req, res) => { if (req.method === 'GET') { res.send('hello') } else if (req.method === 'POST') { const user = auth(req, res) console.log('do other things') res.send(`welcome! ${user.name}`) }}
但在 Next.js, 咱们没有任何方法停止申请。实践上 console.log('do other things')
在用户未登录时不应该被执行。
应用 next-connect
要在 Next.js 中像 Express/Koa 这样应用 connect 中间件,咱们能够应用 next-connect 这个库。
装置
next-connect
:$ yarn add next-connect
当初,让咱们用 next-connect
重写下面的例子:
// pages/api/example.tsimport nc from 'next-connect'function authMiddleware(req, res, next) { res.status(403) res.send('please sign in first')}// 用 `nc()` 创立一个 api handlerconst handler = nc() .get((req, res) => { res.send('hello') }) .post(authMiddleware, (req,res) => { res.send('hello') })export default handler
能够看到,当初咱们在 Next.js 的API route 能够像在 Express 一样应用中间件。
在 authMiddleware
中,咱们返回了一个 403,并且没有执行 next()
, 模仿了用户未登录的状况。因为 next()
没有执行,这个 POST 申请不会执行这个 POST handler 的代码。
用 next-connect
的另一个益处是,咱们能够用.get()
, .post()
, put()
这样的 helper 来创立对应的 handler, 而不须要用 if (req.method === XXX)
这样的判断。让代码更好读。
因为 next-connect
兼容 connect 中间件,所以咱们能够间接用社区上成熟的 connect 中间件,例如用于批改跨域设置的中间件 cors
:
装置
cors
:$ yarn add cors
// pages/api/example.tsimport nc from 'next-connect'+ import * as cors from 'cors'const corsOptions = { origin: 'http://example.com', optionsSuccessStatus: 200}const handler = nc()+ .use(cors(corsOptions)) .get((req, res) => { res.send('hello') }) .post(authMiddleware, (req,res) => { res.send('hello') })export default handler