ノードJSにおけるエクスプレスミドルウェアの実現原理の分析

1つ、エクスプレス

  1. express ミドルウェアは次のとおりです。
  • app.use ミドルウェアの登録に使用され、最初に収集します
  • ミートhttpに従い要求、pathおよびmethodどのような判断トリガー
  • 実現nextメカニズム、すなわちnext
  1. express ミドルウェア実現の内部原則であるコードは次のとおりです。
const http = require('http')
const slice = Array.prototype.slice

class LikeExpress {
    
    
  constructor () {
    
    
    // 存放中间件的列表
    this.routes = {
    
    
      all: [], // app.use(...)
      get: [], // app.get(...)
      post: [] // app.post(...)
    }
  }


  register (path) {
    
    
    const info = {
    
    }
    // 判断第一个参数是否是 string 类型
    if (typeof path === 'string') {
    
    
      info.path = path
      // 从第二个参数开始,转换为数组,存入 stack
      info.stack = slice.call(arguments, 1)
    } else {
    
    
      info.path = '/'
      // 从第一个参数开始,转换为数组,存入 stack
      info.stack = slice.call(arguments, 0)
    }
    return info
  }


  use () {
    
    
    const info = this.register.apply(this, arguments)
    this.routes.all.push(info)
  }


  get () {
    
    
    const info = this.register.apply(this, arguments)
    this.routes.all.push(info)
  }


  post () {
    
    
    const info = this.register.apply(this, arguments)
    this.routes.all.push(info)
  }


  match (method, url) {
    
    
    let stack = []
    if (url === '/favicon.ico') {
    
    
      return stack
    }

    // 获取 routes 
    let cutRoutes = []
    cutRoutes = cutRoutes.concat(this.routes.all)
    cutRoutes = cutRoutes.concat(this.routes[method])

    cutRoutes.forEach(routeInfo => {
    
    
      if (url.indexOf(routeInfo.path) === 0) {
    
    
        // url === '/api/get-cookie' 且 routeInfo.path === '/'
        // url === '/api/get-cookie' 且 routeInfo.path === '/api'
        // url === '/api/get-cookie' 且 routeInfo.path === '/api/get-cookie'
        stack = stack.concat(routeInfo.stack)
      }
    })
    return stack
  }

  // 核心的 next 机制
  handle(req, res, stack) {
    
    
    const next = () => {
    
    
      // 拿到第一个匹配的中间件
      const middleware = stack.shift()
      if (middleware) {
    
    
        // 执行中间件函数
        middleware(req, res, next)
      }
    }
    next()
  }


  callback () {
    
    
    return (req, res) => {
    
    
      res.json = (data) => {
    
    
        res.setHeader('Content-type', 'application/json')
        res.end(JSON.stringify(data))
      }

      const url = req.url
      const method = req.method.toLowerCase()
      
      const resultList = this.match(method, url)
      this.handle(req, res, resultList)
    }
  }


  listen (...args) {
    
    
    const server = http.createServer(this.callback())
    server.listen(...args)
  }
}


// 工厂函数
module.exports = () => {
    
    
  return new LikeExpress()
}

  1. express ミドルウェアの原則の適用、コードは次のとおりです。
const express = require('./like-express')


// 本次 http 请求的实例
const app = express()

app.use((req, res, next) => {
    
    
  console.log('请求开始...', req.method, req.url)
  next()
})

app.use((req, res, next) => {
    
    
  // 假设在处理 cookie
  console.log('处理 cookie...')
  req.cookie = {
    
    
    userId: 'abc123'
  }
  next()
})


app.use('/api', (req, res, next) => {
    
    
  console.log('处理 /api 路由')
  next()
})

app.get('/api', (req, res, next) => {
    
    
  console.log('处理 /api 路由')
  next()
})

app.post('/api', (req, res, next) => {
    
    
  console.log('处理 /api 路由')
  next()
})


// 模拟登录验证
function loginCheck(req, res, next) {
    
    
  setTimeout(() => {
    
    
    console.log('模拟登录成功')
    next()
  })
}


app.get('/api/get-cookie', loginCheck, (req, res, next) => {
    
    
  console.log('get /api/get-cookie')
  res.json({
    
    
    errno: 0,
    data: req.cookie
  })
})

app.use((req, res, next) => {
    
    
  console.log('处理 404')
  res.json({
    
    
    errno: -1,
    msg: '404 not found'
  })
})


app.listen(8000, () => {
    
    
  console.log('server is running on port 8000')
})

おすすめ

転載: blog.csdn.net/weixin_42614080/article/details/110914410