1
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

Randy
134 声望11 粉丝

野生前端工程师