Экспресс простая реализация

внешний интерфейс Express

Сегодня мы используемnodeсерединаhttpмодуль реализуетexpressРамка. оhttpПо использованию модуля можно проконсультироваться самостоятельноСвязанная документация.

1. Внедрить услугу экспресс-запуска

Роднойexpressзапустить службу

let express = require('express')
let app = express()
let server = app.listen(3000, 'localhost', function () {
	console.log(`app is listening at http://${server.address().address}:${server.address().port}`)
})

Если вышеуказанные функции реализованы, первое, что мы определяем, этоexpressэто функция, которая возвращаетappфункция, иlistenметод, мы могли бы также назвать этоappФункция является функцией слушателя. Код реализации выглядит следующим образом:

let http = require('http')
function createApplication () {
  // app是一个监听函数
  let app = function (req, res) {
    res.end('hello world')
  }
  app.listen = function () {
    let server = http.createServer(app)
    // arguments就是参数(3000, 'localhost', function () {})
    server.listen(...arguments)
    return server
  }
  return app
}
module.exports = createApplication

2. Внедрить экспресс-маршрутизацию

Роднойexpressиспользовать маршрутизацию

let express = require('express')
let app = express()
app.get('/name', function (req, res) {
  res.end('get name')
})
app.listen(3000, 'localhost', function () {
  console.log('app is listening')
})

Если вышеуказанные функции реализованы, нашаappФункция прослушивателя должна реализоватьgetметод, который может сохранить этот вызов вappВ массиве маршрутов при успешном запуске службы соответствующий обратный вызов может быть вызван при отслеживании соответствующего маршрута. Код реализации выглядит следующим образом:

let http = require('http')
function createApplication () {
  // app是一个监听函数
  let app = function (req, res) {
    // 当前请求方法
    let m = req.method.toLocaleLowerCase()
    // 当前请求路径
    let { pathname } = url.parse(req.url, true)
    for (let i = 0; i < app.routes.length; i++) {
      let { path, method, handler } = app.routes[i]
      // 如果该路由项匹配到当前请求,则执行回调
      if (path === pathname && method === m) {
        handler(req, res)
      }
    }
  }
  // 存储所有的请求,以便监听函数调用
  app.routes = []
  app.get = function (path, handler) {
    let layer = {
      path,
      method: 'get',
      handler
    }
    app.routes.push(layer)
  }
  // app.listen = function () {}
  return app
}
module.exports = createApplication

разноеRESTFULМетод тот же. Код реализации выглядит следующим образом:

let http = require('http')
function createApplication () {
  // app是一个监听函数
  let app = function (req, res) {
    // 当前请求方法
    let m = req.method.toLocaleLowerCase()
    // 当前请求路径
    let { pathname } = url.parse(req.url, true)
    for (let i = 0; i < app.routes.length; i++) {
      let { path, method, handler } = app.routes[i]
      // 如果该路由项匹配到当前请求,则执行回调
      if ((path === pathname || path === '*') && (method === m || method === 'all')) {
        handler(req, res)
      }
    }
  }
  // 存储所有的请求,以便监听函数调用
  app.routes = []
  // http.METHODS 获取RESTFUL所有方法
  http.METHODS.forEach(method => {
    method = method.toLocaleLowerCase()
    app[method] = function (path, handler) {
      let layer = {
        method,
        path,
        handler
      }
      app.routes.push(layer)
    }
  })
  // 如果没有匹配成功,最终执行all函数所存储的回调
  app.all = function (path, handler) {
    let layer = {
      method: 'all', // 表示全部匹配
      path,
      handler
    }
    app.routes.push(layer)
  }
  // app.listen = function () {}
  return app
}
module.exports = createApplication

3. Внедрить экспресс промежуточное ПО

РоднойexpressИспользовать промежуточное ПО

let express = require('express')
let app = express()
app.use(function (req, res, next) {
  res.setHeader('Content-Type', 'text/html; charset=utf-8')
  next()
})
app.use('/name', function (req, res, next) {
  next()
})
app.get('/name', function (req, res) {
  res.end('获取姓名')
})
app.listen(3000, 'localhost', function () {
  console.log('app is listening')
})

Отсюда видно, чтоuseМетоды иmethodМетод аналогичен, основное внимание уделяется достижениюnextметод.nextФункция функции состоит в том, чтобы изменить некоторые контексты до поступления запроса, такие как изменение кодировки возвращаемого набора символов и т. д., и выполнить ее последовательно, что может быть реализовано итеративным образом. Код реализации выглядит следующим образом:

let http = require('http')
let url = require('url')
function createApplication () {
  // app是一个监听函数
  let app = function (req, res) {
    // 当前请求方法
    let m = req.method.toLocaleLowerCase()
    // 当前请求路径
    let { pathname } = url.parse(req.url, true)
    // 迭代次数索引
    let index = 0
    // 用next代替for循环
    function next () {
      // 如果全部路由数组都不满足,则返回找不到
      if (index === app.routes.length) {
        return res.end(`can not ${m} ${pathname}`)
      }
      // 处理中间件
      let { method, path, handler } = app.routes[index++]
      if (method === 'middle') {
        // 如果该中间件path是/,匹配全部请求,执行回调;如果相等,执行回调;如果该中间件path被包含在当前请求url中,也执行回调
        if (path === '/' || path === pathname || pathname.startsWith(path + '/')) {
          handler(req, res, next)
        } else {
          next()
        }
      } else {
        if ((path === pathname || path === '*') && (method === m || method === 'all')) {
          handler(req, res, next)
        } else {
          next()
        }
      }
    }
    // 直接调用next函数,根据路径匹配查找对应回调并执行
    next()
  }
  // app.routes = []
  // http.METHODS.forEach(() => {}
  // app.all = function (path, handler) {}
  // 中间件:参数可以传path,也可以不传,默认'/'
  app.use = function (path, handler) {
    if (typeof handler !== 'function') {
      handler = path
      path = '/'
    }
    let layer = {
      method: 'middle',
      path,
      handler
    }
    app.routes.push(layer)
  }
  // app.listen = function () {}
  return app
}
module.exports = createApplication

В настоящее время,expressРеализована основная функция, посмотрим пройдет ли ошибка выполненияnextСлучай, когда возвращаются параметры функции. еслиnextУ функции есть параметры, она пропустит все следующие промежуточные программы и маршрутизацию и вернет сообщение с параметрами ошибки напрямую, поэтому перед обработкой промежуточных программ вы должны сначала оценить ситуацию с ошибкой и продолжить передачу ошибки, только той, что с четырьмя параметры совпадают Выполняется при вызове обратного вызова. Код реализации выглядит следующим образом:

let http = require('http')
function createApplication () {
  // app是一个监听函数
  let app = function (req, res) {
    // 此处省略...
    function next (err) {
      // 此处省略...
      if (err) {
        res.end(err)
        if (handler.length === 4) {
          handler(err, req, res, next)
        } else {
          next(err)
        }
      } else {
        // 处理中间件,此处省略...
      }
    }
    next()
  }
  // app.routes = []
  // http.METHODS.forEach(() => {}
  // app.all = function (path, handler) {}
  // app.use = function (path, handler) {}
  // app.listen = function () {}
  return app
}
module.exports = createApplication

исходный код

Что ж, весь код был приведен здесь, давайте остановимся~ 😋😋😋