美文网首页前端开发那些事儿
原生node封装一个类似express的路由(二)

原生node封装一个类似express的路由(二)

作者: 踏莎行 | 来源:发表于2021-07-02 12:39 被阅读0次

上一节

(末尾含完整程序)
上一节做了对get,post请求的处理,这一节做静态资源访问。

处理静态资源访问的原因

  • 如果客户端请求的数据是静态页面或者资源文件,就需要处理一下,返回对应文件的数据,如果不处理的话,就会按照路由匹配处理,这样就是匹配不到,就会404了。
  • 比如在html文件中引入了css文件,所以也要去请求这个css文件,同样不做静态资源访问,也会当路由处理

开始

  • 首先配置一下静态资源的目录名称,一般大家的目录名称以static和public比较多,这里将目录名称设为默认的static,当然也可以动态修改,相当于设置了default。
let server = () => {
  let G = {
    _post: {},
    _get: {},
    staticPath: 'static'
  }
  let app = function (req, res) {...}

  app.get = function (str, cb) {...}

  app.post = function (str, cb) {...}

  // 配置静态web服务目录
  app.static = function (staticPath) {
    G.staticPath = staticPath
  }

  return app
}

为G对象新增一个staticPath属性,存储静态目录名称,给app函数新增一个static方法,用来动态修改静态资源目录名称,参数字符串的目录名称

  • 封装处理静态资源的函数
    引入fs,path模块
const path = require('path')
const fs = require('fs')

function initStatic(req, res, staticPath) {
  // 获取请求的路径 /css/style.css   /login
  // 包括路由和静态资源文件
  let pathname = url.parse(req.url).pathname
  // 使用path模块的extname,获取请求路径的后缀名
  let extname = path.extname(pathname)
  // 判断一下后缀名存不存在,没有后缀名extname 就是空,如果非空就访问静态资源文件
  if (extname) {
    try {
      /**
       * 以异步的方法读取静态资源文件,app.js和静态资源是同一级的目录,所以使用了'./'
       * - app.js
       * - public/static
       * 所以如,文件的路径就是'./static/css/style.css’
       */
      let data = fs.readFileSync('./' + staticPath + pathname)
      if (data) {
        /**
          * 如果获取到了,执行
          * 静态资源的文件格式多种多样,如.css,.js.jpg,.json等,所以响应头的类型就要做特殊处理了,返回正确与之对应的文件类型
         * 这里也就封装了一个getFileMine方法(下面介绍),用于获取文件的类型
         * 然后把响应的文件类型动态拼接到响应头就行了
         */
        let mime = getFileMine(extname)
        res.writeHead(200, { "Content-Type": '' + mime + ";charset=utf-8" })
        // 最后返回数据
        res.end(data)
      }
    } catch (error) {
      console.log(error);
    }
  }
}

目录结构
data\
--mime.json
static\
modules\
--route.js
app.js

// 参数就是文件后缀名
function getFileMine(extname) {
  // 读取mime.json文件,并转换成对象格式
  var data = fs.readFileSync('./data/mime.json')
  let mineObj = JSON.parse(data.toString())
  // 然后返回文件类型
  return mineObj[extname]
}

最后在app函数中配置一下一下

  let app = function (req, res) {
    changeRes(res);
    //配置静态web服务
    initStatic(req, res, G.staticPath);
    ...
}

app.js文件里使用route.js

const http = require('http')
const app = require('./modules/route')
http.createServer(app).listen(3000);

// 配置静态资源访问
app.static("static")

// 配置路由
app.get('/login', function (req, res) {
})

app.post('/doLogin', function (req, res) {
  console.log(req.body);
  res.send(req.body)
})

app.get('/', function (req, res) {
  res.send("home")
})

ok,基本完成了

完整代码(route.js)

const url = require('url')
const path = require('path')
const fs = require('fs')

/**
 * 
 * @param {obj} res 扩展res
 */
function changeRes(res) {
  res.send = (data) => {
    res.writeHead(200, {
      "Content-Type": "text/html;charset=utf-8"
    })

    res.end(data)
  }
}


/**
 * 根据后缀名获取文件类型
 * @param {string} extname 文件的后缀名
 * @returns 
 */
function getFileMine(extname) {
  // 使用promise异步获取
  // return new Promise((resolve, reject) => {
  //   fs.readFile('./data/mime.json', (err, data) => {
  //     if (err) {
  //       console.log(err);
  //       return;
  //     }
  //     let mineObj = JSON.parse(data.toString())
  //     resolve(mineObj[extname])
  //   })
  // })

  var data = fs.readFileSync('./data/mime.json')
  let mineObj = JSON.parse(data.toString())
  return mineObj[extname]
}

function initStatic(req, res, staticPath) {
  let pathname = url.parse(req.url).pathname
  let extname = path.extname(pathname)
  console.log(extname);
  if (extname) {
    try {
      let data = fs.readFileSync('./' + staticPath + pathname)
      if (data) {
        let mime = getFileMine(extname)
        res.writeHead(200, { "Content-Type": '' + mime + ";charset=utf-8" })
        // console.log(pathname);
        res.end(data)
      }
    } catch (error) {
      console.log(error);
    }
  }
}

let server = () => {
  let G = {
    _post: {},
    _get: {},
    staticPath: 'static'
  }
  let app = function (req, res) {
    changeRes(res);
    initStatic(req, res, G.staticPath);

    let pathname = url.parse(req.url).pathname;
    let method = req.method.toLowerCase();
    let extname = path.extname(pathname);
    if (!extname) {  //如果有后缀名用静态web处理
      if (G['_' + method][pathname]) {
        if (method == "get") {
          G['_' + method][pathname](req, res); 
        } else {
          let postData = '';
          req.on('data', (chunk) => {
            postData += chunk;
          })
          req.on('end', () => {
            req.body = postData;
            G['_' + method][pathname](req, res); 
          })

        }

      } else {
        res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' });
        res.end('页面不存在');
      }
    }
  }

  app.get = function (str, cb) {
    G._get[str] = cb
  }

  app.post = function (str, cb) {
    G._post[str] = cb
  }

  app.static = function (staticPath) {
    G.staticPath = staticPath
  }

  return app
}


module.exports = server()

相关文章

网友评论

    本文标题:原生node封装一个类似express的路由(二)

    本文链接:https://www.haomeiwen.com/subject/bfeeultx.html