乐趣区

关于前端:在-Nextjs-使用-connect-中间件

本文节选自 Next.js 利用开发实际

Next.js 没有中间件机制。首先让我简略解释一下什么是中间件,为什么咱们须要中间件。

在 Express/Koa, 咱们能够用中间件进入一个申请的生命周期,一个典型的中间件是一个函数,它承受 req, resnext 参数:

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
退出移动版