原生NodeJS封装Express路由

Express:https://www.expressjs.com.cn/

express路由:

var express = require('express')
var app = express()
app.get("/", function (req, res) {
res.send('hello world')
})
app.get("/login", function (req, res) {
res.send('hello world')
})
app.post("/doLogin", function (req, res) {
res.send('POST request to the homepage')
})

考虑定义一个 Router 模块,Router 模块中绑定一个 get 方法配置路由和一个 post 方法配置路由,以及一个 error 方法处理路由出错情况,并向外暴露 Router 模块,外部调用这个模块时,只需要传入一个路由和路由回调执行路由逻辑。

在 get 方法和post 方法中,首先需要在全局变量 Global 中注册一个路由,把我们外部传入的路由和路由回调绑定到 Global 中,在调用Router 模块时,就可以先判断是否这个路由是否注册了,没有注册,就执行 Router的 error 方法报 404,注册了就执行这个路由的路由回调逻辑。

const url = require('url')
const Global = { }
const Router = function (req, res) { const pathname = url.parse(req.url).pathname if (Global[pathname]) { //如果是注册过的路由,就执行路由回调 Global[pathname](req, res) } else { Router.error(req, res) } } //给Router绑定get方法配置路由 Router.get = function (str, callback) { Global[str] = callback;//注册路由 }
//给Router绑定post方法配置路由
Router.post = function (str, callback) {
    Global[str] = callback;//注册路由
}
//给Router绑定error方法,路由未注册时报404 Router.error = function (req, res) { res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' }); res.end("404 error") } //将Router模块向外暴露出去 module.exports = Router;

外部调用:

Router.get('/login',function(req,res){
    res.end('login')
})

以上的Router模块 以及 Global 全部暴露在全局中,容易污染全局,所以可以将Router 封装到一个 Request 模块中,Request 模块的返回值就是 Router配置方法。

get路由注册和 post路由注册需要有区别,否则 Global [pathname] 都一样,post 路由配置会覆盖 get 路由配置,区分方式是在 Global 中绑定 _get 和 _post 两个属性,在注册路由时,如果是 get类型就注册 Global._get 路由,是 post类型,就注册 Global._post 路由

Global 中的 _get 和 _post 两种路由的执行,在执行之前先判断 reg的请求类型,拿到 reg.method,根据这个执行不同的路由回调,是 get 类型,直接执行 _get 路由逻辑,是 post 类型,可以拿到 post 请求中的参数,将这个参数放在 req.body 中,在执行 _post 的路由逻辑。

当然,路由没有注册( pathname不匹配 ),就执行路由错误报404

最后返回封装的路由方法给 Request 模块。

const url = require('url')

const Request = function(){
    const Global = {
        "_get":{ }, //把get和post分开
        "_post":{ },
    } 

    const Router = function (req, res) {
        const pathname = url.parse(req.url).pathname
        const method = req.method.toLowerCase() //获取请求类型 get/post

        if (Global['_'+method][pathname]) { //拿到请求类型,直接通过Global执行相应类型的请求
            if(method=='get'){
                Global['_get'][pathname](req, res)
            }
            else if(method=='post'){
                let params = '';
                req.on('data',(chunk)=>{
                    params+=chunk;
                })
                req.on('end',()=>{
                    req.body=params
                    Global['_post'][pathname](req,res)
                })
            }
        }
        else {
            Router.error(req, res)
        }
    }

    //给Router绑定get方法配置路由
    Router.get = function (str, callback) {
        Global['_get'][str] = callback;//注册路由
    }

    //给Router绑定post方法配置路由
    Router.post = function (str, callback) {
        Global['_post'][str] = callback;//注册路由
    }

    //给Router绑定error方法,路由未注册时报404
    Router.error = function (req, res) {
        res.writeHead(404, { 'Content-Type': 'text/html;charset="utf-8"' });
        res.end("404 error")
    }
    return Router;
}
//将Request模块向外暴露出去
module.exports = Request();

外部调用这个Request模块的路由配置方法,配置路由:

const http = require('http');
const ejs = require('ejs')
const Request = require('./Router02')
//注册web服务
http.createServer(Request).listen(8081);

//配置路由
Request.get('/', function (req, res) {
    res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
    res.end('<h3>这是首页</h3>');
})
Request.get('/login',function(req,res){
    ejs.renderFile('./views/form.ejs', {}, (err, data) => {
        res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
        res.end(data);
    })
})
Request.post('/doLogin', function (req, res) {
    res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
    console.log(req.body)
    res.end(req.body);
})
Request.get('/register',function(req,res){
    res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
    res.end('<h3>这是注册页</h3>');
})
console.log('Server running at http://127.0.0.1:8081/');

路由配置正常:

下面将响应信息封装成一个 send() 方法:

在 Router中可以修改 res ,扩展 res的方法:

Router 中可以封装一个静态web服务,这样可以既直接访问静态资源,也可以执行后端路由逻辑:

Router.js

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

//web静态服务
function staticWeb(req,res,staticPath){
    let pathname = url.parse(req.url).pathname  //先获取地址
    pathname = pathname == '/' ? '/index.html' : pathname //根目录下定位到首页
    let ext = path.extname(pathname) //获取文件后缀名
    let getMime = function (ext) { //获取文件类型
        let data = fs.readFileSync('./mime.json'); //同步方法,没有回调
        let mime = JSON.parse(data.toString())[ext]
        return mime;
    }
    try {
        let data = fs.readFileSync(staticPath + pathname)
        if (data) {
            let mime = getMime(ext) //获取文件类型
            res.writeHead(200, { 'Content-Type': `${mime};charset="utf-8"` });
            res.end(data);
        }
    } catch (error) {
        console.log("静态资源没有匹配,执行匹配后端路由")
    }
}


const Request = function(){
    const Global = {
        "_get":{ }, //把get和post分开
        "_post":{ },
        staticPath:'./static' //设置默认静态web目录
    } 
    const Router = function (req, res) {
        const pathname = url.parse(req.url).pathname //获取访问的路由
        const method = req.method.toLowerCase() //获取请求类型 get/post
        //给 res 扩展一个send()方法响应请求
        res.send=function(data){
            res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
            res.end(data);
        }
        //配置静态web服务
        staticWeb(req,res,Global.staticPath)

        if (Global['_'+method][pathname]) { //拿到请求类型,直接通过Global执行相应类型的请求
            if(method=='get'){
                Global['_get'][pathname](req, res)
            }
            else if(method=='post'){
                let params = '';
                req.on('data',(chunk)=>{
                    params+=chunk;
                })
                req.on('end',()=>{
                    req.body=params
                    Global['_post'][pathname](req,res)
                })
            }
        }
        else {
            Router.error(req, res)
        }
    }

    //给Router绑定get方法配置路由
    Router.get = function (str, callback) {
        Global['_get'][str] = callback;//注册路由
    }

    //给Router绑定post方法配置路由
    Router.post = function (str, callback) {
        Global['_post'][str] = callback;//注册路由
    }

    //给Router绑定error方法,路由未注册时报404
    Router.error = function (req, res) {
        res.send("404 error")
    }

    //配置静态web服务,传入一个静态目录地址即可,不传的话取Global中的默认路径
    Router.static = function(staticPath){
        Global.staticPath=staticPath
    }
    return Router;
}
//将Request模块向外暴露出去
module.exports = Request();

app.js

const http = require('http');
const ejs = require('ejs')
const Request = require('./Router04')
//注册web服务
http.createServer(Request).listen(8081);

//配置路由
Request.get('/', function (req, res) {
    res.send('<h3>这是首页</h3>');
})
Request.get('/login',function(req,res){
    ejs.renderFile('./views/form.ejs', {}, (err, data) => {
        res.send(data);
    })
})
Request.post('/doLogin', function (req, res) {
    res.send(req.body);
})
Request.get('/register',function(req,res){
    res.send('<h3>这是注册页</h3>');
})
console.log('Server running at http://127.0.0.1:8081/');

静态资源访问正常,后端路由也执行正常:

原文地址:https://www.cnblogs.com/shanlu0000/p/13156790.html