Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

手写express框架(简洁版) #23

Open
iloveyou11 opened this issue Apr 30, 2021 · 0 comments
Open

手写express框架(简洁版) #23

iloveyou11 opened this issue Apr 30, 2021 · 0 comments
Labels

Comments

@iloveyou11
Copy link
Owner

iloveyou11 commented Apr 30, 2021

采用express第三方包实现的话,app.js如下:

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

// 我们在这里模拟一些get、post方法
app.get('/', (req, res) => {
    res.end('welcome')
})
app.get('/name', (req, res) => {
    res.end('yyyyy')
})
app.get('/age', (req, res) => {
    res.end('12')
})
app.post('/name', (req, res) => {
    res.end('yes!')
})

app.listen(3000, () => {
    console.log('3000');
})

这时,我们执行这个js文件,可以发现3000端口已启动,可以通过http://localhost:3000访问页面。

接下来我们需要做一件事情,就是自己实现express的路由机制。首先创建express.js文件并导出一个方法,这个方法需要产生app对象(因为上述代码是采用express()实现的),开始搭建基本骨架:

const http = require('http')

// 这个方法 return app(产生一个app对象),其中有listen方法(启动服务器,监听指定端口)
function createApplication() {
  let app = (req, res) => { }

  app.listen = function () {
    let server = http.createServer(app)
    server.listen(...arguments)
  }

  return app
}

// 导出一个方法
module.exports = createApplication

接下来,我们先来实现get请求,思路如下:

  1. 创建app.routes数组,里面存放每一个路由信息(包括methodpath、回调函数handler
  2. 通过app.get方法,向app.routes放入每个路由信息
  3. 拿到传入的methodpath,遍历app.routes,找到对应的handler并执行
const http = require('http')
const url = require('url')

function createApplication() {
  let app = (req, res) => {
    let reqMethod = req.method.toLowerCase() // 获取请求的方法
    let { pathname } = url.parse(req.url, true) // 获取请求路径
    // 根据方法和路径匹配成功后执行对应的回调函数
    for (let i = 0; i < app.routes.length; i++) {
      let {
        method,
        path,
        handler
      } = app.routes[i]
      // 拿到传入的`method`和`path`,遍历`app.routes`,找到对应的`handler`并执行
      if (reqMethod === method && pathname === path) {
        handler(req, res)
        return
      }
    }
    res.end('cannot find')
  }

  // 创建`app.routes`数组,里面存放每一个路由信息(包括`method`、`path`、回调函数`handler`)
  app.routes = []

  // 通过`app.get`方法,向`app.routes`放入每个路由信息
  app.get = function (path, handler) {
    let layer = {
      method: 'get',
      path,
      handler
    }
    app.routes.push(layer)
  }

  app.listen = function () {
    let server = http.createServer(app)
    server.listen(...arguments)
  }

  return app
}

module.exports = createApplication

我们实现了get请求了,接下来要实现其他的请求方法,如post、put、delete等等,但是method如此之多,一个个写肯定不是最明智的选择,因此我们选择批量生产方法的形式,通过http.METHODS拿到所有的method,实现批量挂载:

const http = require('http')
const url = require('url')

function createApplication() {
  let app = (req, res) => {
    // 获取请求的方法
    let m = req.method.toLowerCase()
    let { pathname } = url.parse(req.url, true)

    // 取出每一个layer
    // 根据方法和路径匹配成功后执行对应的回调函数
    for (let i = 0; i < app.routes.length; i++) {
      let {
        method,
        path,
        handler
      } = app.routes[i]
      if (m === method && pathname === path) {
        handler(req, res)
        return
      }
    }
    res.end('cannot find')
  }

  app.routes = []


  // 注意:这里是新增

  // 批量生产方法
  http.METHODS.forEach(method => {
    method = method.toLowerCase()
    app[method] = function (path, handler) {
      let layer = {
        method,
        path,
        handler
      }
      app.routes.push(layer)
    }
  })

  // console.log(http.METHODS);
  // [ 'ACL',     
  // 'BIND',    
  // 'CHECKOUT',
  // 'CONNECT', 
  // 'COPY',
  // 'DELETE',
  // 'GET',
  // 'HEAD',
  // 'LINK',
  // 'LOCK',
  // 'M-SEARCH',
  // 'MERGE',
  // 'MKACTIVITY',
  // 'MKCALENDAR',
  // 'MKCOL',
  // 'MOVE',
  // 'NOTIFY',
  // 'OPTIONS',
  // 'PATCH',
  // 'POST',
  // 'PROPFIND',
  // 'PROPPATCH',
  // 'PURGE',
  // 'PUT',
  // 'REBIND',
  // 'REPORT',
  // 'SEARCH',
  // 'SOURCE',
  // 'SUBSCRIBE',
  // 'TRACE',
  // 'UNBIND',
  // 'UNLINK',
  // 'UNLOCK',
  // 'UNSUBSCRIBE' ]

  app.listen = function () {
    let server = http.createServer(app)
    server.listen(...arguments)
  }

  return app
}

module.exports = createApplication

到此,已实现全部请求方法的挂载。但还存在许多需要完善的地方,比如:

  1. 尚不支持params、query、request body等传参
  2. 未添加安全机制
  3. 其他express api均未实现
  4. ……

未来我将会不断完善

@iloveyou11 iloveyou11 added the js label Apr 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant