Express 和 Koa2 的中间件神操作,你会几个?

213 阅读2分钟

express作者和koa是同一个团队,重点学koa2,并且研究它的原理。

第一章 Express

文档地址: expressjs.com/en/starter/…

npm install express

Hello world

const express = require('express')
const app = express()

app.get('/', function (req, res) {
  res.send('Hello111 World')
})

app.listen(3000)

路由定义

const express = require('express')
const app = express()

// 后端路由
app.get('/', function (req, res) {
    res.send('我是get')
  })

app.post('/', function (req, res) {
  res.send('我是post')
})

app.post('/user', function (req, res) {
    res.send('我是詹姆斯')
})

app.listen(3000)

静态资源

const express = require('express')
const app = express()

// 引入静态资源访问中间件
// app.use(express.static('public'))
app.use('/static', express.static('public'))

// 后端路由
app.get('/', function (req, res) {
    res.send('我是get')
})

app.post('/', function (req, res) {
  res.send('我是post')
})

app.post('/user', function (req, res) {
    res.send('我是詹姆斯')
})

app.listen(3000)

中间件

const express = require('express')
const app = express()

// 后端路由
app.get('/', function (req, res) {
    res.send('我是get')
})

app.use((req, res, next) => {
    // console.log('Time:', Date.now())
    console.log(11111)
    next()
    console.log(2222)
})

app.use((req, res, next) => {
    // console.log('Time:', Date.now())
    console.log(3333)
    next()
    console.log(4444)
})

app.listen(3000)

第二章 Koa

快速开始

安装

// 初始化package.json
npm init// 安装koa2 
npm install koa

一个hello world

新建一个index.js,敲上以下代码

//index.js
const Koa = require('koa')
const app = new Koa()

app.use(async (ctx, next) => {

    // ctx有两个核心属性 request response
    // 这两个属性实际上是基于node的原生request response进行简化和封装之后的
    ctx.response.body = '你好,我是内地吴彦祖'
    console.log(ctx.res)
    
})

app.listen(3333, () => {
    console.log('server is running at http://localhost:3333')
})

在我们的命令行敲上

node index.js

几个核心概念

中间件好基友ctx和next

在上面的代码中,我们可以看到app.use后面使用了2个参数,ctxnext,下面我们介绍一个这哥俩到底干嘛的

ctx

ctx作为上下文使用,Koa将 node 的 request, response 对象封装进一个单独对象。即ctx.requestctx.response。Koa 内部又对一些常用的属性或者方法做了代理操作,使得我们可以直接通过 ctx 获取。比如,ctx.request.url 可以写成 ctx.url

next

next 参数的作用是将处理的控制权转交给下一个中间件

大名鼎鼎的洋葱模型。

image.png

image.png 经典的洋葱图概念能很好的解释next的执行,请求从最外层进去,又从最里层出来。我们看一个例子

const Koa = require('koa')
const app = new Koa()

app.use(async (ctx, next)=>{
  let startTime = new Date().getTime()
  await next()
  let endTime = new Date().getTime()
  console.log(`此次的响应时间为:${endTime - startTime}ms`)
})

app.use(async (ctx, next) => {
  console.log('111, 然后doSomething')
  await next()
  console.log('111 end')
})

app.use(async (ctx, next) => {
  console.log('222, 然后doSomething')
  await next()
  console.log('222 end')
})

app.use(async (ctx, next) => {
  console.log('333, 然后doSomething')
  await next()
  console.log('333 end')
})

app.listen(3333, ()=>{
  console.log('server is running at http://localhost:3333')
})

看一下运行结果:

image.png

路由 koa-router

我们常用koa-router来处理URL

安装

npm i koa-router --save

看一个例子:

const Koa = require('koa')
const app = new Koa()
const Router = require('koa-router')

const router = new Router()

router.get('/', async (ctx, next) => {
  ctx.body = '你好,我这里是index页'
})

router.get('/user', async (ctx, next) => {
  ctx.body = '你好,我这里是user页'
})

router.get('/error', async (ctx, next) => {
  ctx.body = '你好,我这里是error页'
})

app.use(router.routes())

app.listen(3333, ()=>{
  console.log('server is running at http://localhost:3333')
})

koa-router也支持嵌套写法,通过一个总路由装载所有子路由,也非常的方便。看一个例子:

const Koa = require('koa')
const app = new Koa()
const Router = require('koa-router')

// 子路由1
let oneRouter = new Router()
oneRouter.get('/', async (ctx, next) => {
  ctx.body = '你好,我这里是oneRouter页'
})

// 子路由2
let twoRouter = new Router()
twoRouter.get('/', async (ctx, next) => {
  ctx.body = '你好, 我这里是twoRouter页'
}).get('/home', async (ctx , next) => {
  ctx.body = '你好, 我这里是home页'
})

// 装载所有子路由let indexRouter = new Router()

indexRouter.use('/one',oneRouter.routes(), oneRouter.allowedMethods())
indexRouter.use('/two',twoRouter.routes(), twoRouter.allowedMethods())

app
  .use(indexRouter.routes())
  .use(indexRouter.allowedMethods())

app.listen(3333, ()=>{
  console.log('server is running at http://localhost:3333')
})

获取请求数据

koa-router提供了常见的 .get .put .post .del 接口来处理各种需求。实际开发中我们用的比较多的是get和post,我们来看看get例子:

const Koa = require('koa')
const app = new Koa()
const Router = require('koa-router')
const router = new Router()

router.get('/data', async (ctx , next)=> {
  let url = ctx.url// 从ctx的request中拿到我们想要的数据
  let data = ctx.request.query
  let dataQueryString = ctx.request.querystring

  ctx.body = {
    url,
    data,
    dataQueryString
  }
})

app.use(router.routes())

app.listen(3333, ()=>{
  console.log('server is running at http://localhost:3333')
})

可以看到区别,.query返回的结果是对象,而.querystring返回的是字符串,这个很好理解。(chrome插件显示成json格式)

如果遵从 RESTful 规范,比如请求要以 '/user/:id'的方式发出的话,我们可以用下面的例子来获取到想要的数据

添加代码

router.get('/data/:id', async (ctx, next) => {

  // 也从ctx中拿到我们想要的数据,不过使用的是params对象
  let data = ctx.params

  ctx.body = data
})

接下来我们看看post的例子

我们常用的请求post,它的数据是放在body当中的。这个时候就推荐一个非常常用且好用的中间件-koa-bodyparser

首先安装

npm i koa-bodyparser --save

然后我们在刚才的代码里添加

router.get('/post', async (ctx, next) => {
    // 模拟一段提交页面
  let html = `    
    <form action="/post/result" method="post">
        <p>你长的最像哪位明星</p>
        <input name="name" type="text" placeholder="请输入名字:"/> 
        <br/>
        <p>输入一段你知道的车牌号</p>
        <input name="num" type="text" placeholder="请输入车牌号:"/>
        <br/> 
        <button>确定不改了哦</button>
     </form> `
  ctx.body = html
})

router.post('/post/result', async (ctx, next) => {
  // 我们可以从ctx的request.body拿到提交上来的数据
  let {name, num} = ctx.request.body

  if (name && num) {
    ctx.body = `hello,你最像的明星是:${name},ch你知道的车牌号是:${num}`
  } else {
    ctx.body = '啊哦~你填写的信息有误'
  }
})