This article is an excerpt from Next.js application development practice
Next.js has no middleware mechanism. First, let me briefly explain what middleware is and why we need middleware.
In Express/Koa, we can use middleware to enter the life cycle of a request. A typical middleware is a function that accepts req
, res
and next
parameters:
function exampleMiddleware(req, res, next) {
if (/** ...*/) {
req.foo = 'bar'
next()
} else {
res.statusCode = 403
res.send('forbiddon')
}
}
This middleware model originated from a Node.js Web framework connect . Early Express was also developed based on Connect, so many frameworks are also compatible with this model, so this middleware model is usually called connect middleware.
In middleware, we can:
req
object, which can be obtained by the next middleware or controller.- You can stop the request by not executing
next()
res
to change the response status.
This allows middleware to reuse code between different routes. Assuming that we need to obtain user information based on cookies in a route, we can write this method of obtaining user information as middleware, and then inject the user information into req.user
, so that the route using this middleware can obtain user information req.user
And in the middleware, if it is determined that the user is not logged in, the request can be aborted and 403 is returned.
The following is an example of how to write and use middleware in 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}`)
})
If we were to do the same thing in Next.js, we would do this:
// 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}`)
}
}
But in Next.js, we have no way to abort the request. In theory console.log('do other things')
should not be executed when the user is not logged in.
Use next-connect
To use connect middleware like Express/Koa in Next.js, we can use next-connect .
Install
next-connect
:$ yarn add next-connect
Now, let us rewrite the above example 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
As you can see, now our API route in Next.js can use middleware like in Express.
In authMiddleware
, we returned a 403, and did not execute next()
, simulating the situation where the user is not logged in. Since next()
not executed, this POST request will not execute the code of this POST handler.
Another advantage of using next-connect
is that we can use .get()
such as 060c985625b2b2, .post()
, put()
to create the corresponding handler, instead of using if (req.method === XXX)
. Make the code easier to read.
Because next-connect
compatible with connect middleware, we can directly use mature connect middleware in the community, such as the middleware cors
used to modify cross-domain settings:
Install
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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。