共计 2526 个字符,预计需要花费 7 分钟才能阅读完成。
本文节选自 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.ts
function 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.ts
import nc from 'next-connect'
function authMiddleware(req, res, next) {res.status(403)
res.send('please sign in first')
}
// 用 `nc()` 创立一个 api handler
const 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.ts
import 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