原生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/');
静态资源访问正常,后端路由也执行正常:




浙公网安备 33010602011771号