我们想要仿照express来封装我们的路由,我们先来看看一个仿照express封装的一个简单路由demo,这有助于我们了解express,然后我们会一步步来实现我们自己的简单express路由。
主入口:
//index.js
var route = require('./model/http-route.js');
var app = route();
var http = require('http');
var ejs=require('ejs');
var server = http.createServer(app);
app.get('/', function (req, res) {
res.send('首页');
});
app.get('/login', function (req, res) {
res.send('login');
});
app.get('/register', function (req, res) {
res.send('register');
});
app.get('/dologin', function (req, res) {
ejs.renderFile('views/form.ejs',{},function(err,data){
res.end(data);
});
});
app.post('/test', function (req, res) {
console.log('POST', req.query);
res.send(req.query);
});
server.listen(8080, function () {
console.log('listen ' + server.address().port);
});
http-route.js
var url = require('url');
/**
* 对resquest进行封装
*
* @param {*} res
*/
var packingRes = function (res) {
var end = res.end;
res.end = function (data, encoding, callback) {
if (data && !(data instanceof Buffer) && (typeof data !== 'function')) {
if (typeof data === 'object') {
data = JSON.stringify(data);
} else if (typeof data === 'number') {
data = data.toString();
}
}
end.call(res, data, encoding, callback);
};
res.send = function (data, type) {
res.writeHead(200,
{
'Access-Control-Allow-Origin': '*',
'Content-Type': 'text/' + (type || 'plain') + '; charset=UTF-8'
}
);
res.end(data);
};
res.sendImg = function (data, type, timeout) {
res.writeHead(200,
{
'Access-Control-Allow-Origin': '*',
'Content-Type': 'image/' + (type || 'png'),
'Content-Length': Buffer.byteLength(data),
'Cache-Control': 'max-age=' + (timeout || 5184000)
}
);
res.end(data);
};
return res;
};
/**
* 路由规则
*/
var route = function () {
var self = this;
this._get = {};
this._post = {};
/**
* 处理请求
*
* @param {*} req
* @param {*} res
*/
var handle = function (req, res) {
packingRes(res);
var Url = url.parse(req.url, true);
var pathname = Url.pathname;
if (!pathname.endsWith('/')) {
pathname = pathname + '/';
}
var query = Url.query;
var method = req.method.toLowerCase();
if (self['_' + method][pathname]) {
if (method == 'post') {
// 设置接收数据编码格式为 UTF-8
// req.setEncoding('utf-8');
var postData = '';
// 数据块接收中
req.on('data', function (postDataChunk) {
postData += postDataChunk;
});
// 数据接收完毕,执行回调函数
req.on('end', function () {
try {
postData = JSON.parse(postData);
} catch (e) { }
req.query = postData;
self['_' + method][pathname](req, res);
});
} else {
req.query = query;
self['_' + method][pathname](req, res);
}
} else {
res.send(method + '请求路由地址不存在:' + pathname);
}
};
/**
* 注册get请求
*/
handle.get = function (string, callback) {
if (!string.startsWith('/')) {
string = '/' + string;
}
if (!string.endsWith('/')) {
string = string + '/';
}
self._get[string] = callback;
};
/**
* 注册post请求
*/
handle.post = function (string, callback) {
if (!string.startsWith('/')) {
string = '/' + string;
}
if (!string.endsWith('/')) {
string = string + '/';
}
self._post[string] = callback;
};
return handle;
};
module.exports = function () {
return new route();
};
我们现在开始封装自己的express。
我们先来写一个例子:
var app = function(){
console.log('app');
}
app.get=function(){
console.log('app.get');
}
app.post=function(){
console.log('app.post');
}
app.post(); /*app.post*/
//
app(); /*app*/
console.log(app);
利用上面,我们可以分别来封装我们的get和post方式。
当请求是get的时候,我们执行app.get(),当请求是post的时候,我们执行app.post()。
但是光区分get和post方式是不够的,我们还需要根据不同的请求的 URL 和其他需要的 GET 及 POST 参数,随后路由需要根据这些数据来执行相应的代码。 所以我们还需要注册路由,根据不同的URL来找到对应的路由。
var G={};
var app=function(req,res){
//console.log('app'+req);
if(G['login']){
G['login'](req,res); /*执行注册的方法*/
}
}
//定义一个get方法
app.get=function(string,callback){
G[string]=callback;
//注册方法
//G['login']=function(req,res){
//
//}
}
//执行get方法
app.get('login',function(req,res){
console.log('login '+req);
})
setTimeout(function(){
app('req','res');
},1000);
我们先定义了一个对象G,跟之前一样我们还定义了app 方法,还有get方法。
我们先来看get方法
//定义一个get方法
app.get=function(string,callback){
G[string]=callback;
}
get方法的参数分别为,string是注册的路由名,比如’login’,当你请求/login的时候,他就会找到对应的login路由,callback是回调函数,就是具体路由内容。
我们再来看如何去注册一个路由。
app.get('login',function(req,res){
console.log('login '+req);
})
我们调用了app.get方法。给它传了一个login的路由名,和一个回调函数。输出了一段文字。
上面这一段的效果相当于:
app.get=function(string,callback){
G[string]=callback;
//注册方法
//G['login']=function(req,res){
//
//}
}
给G对象添加了一个login方法。就像我们之前写的路由一样:
module.exports = {
login : function(req,res){
console.log('login '+req);
},
}
我们再来看看app方法,这是路由的入口,也是程序的入口,根据不同的URL信息来找到对应的路由方法。
var app=function(req,res){
//console.log('app'+req);
if(G['login']){
G['login'](req,res); /*执行注册的方法*/
}
}
我们这里直接写死了请求login路由,实际上我们可以从request中获得url,得到我们要请求的路由,然后使用
if(G[routerName]){
G[routerName](req,res); /*执行注册的方法*/
}
最后我们只需要执行:
setTimeout(function(){
app('req','res');
},1000);
我们继续改造我们的express,我们要把他放到服务器上去,然后要根据我们访问url,去请求指定的路由。
var http=require('http');
var url=require('url');
var G={};
//定义方法开始结束
var app=function(req,res){
//console.log('app'+req);
var pathname=url.parse(req.url).pathname;
if(!pathname.endsWith('/')){
pathname=pathname+'/';
}
if(G[pathname]){
G[pathname](req,res); /*执行注册的方法*/
}else{
res.end('no router');
}
}
//定义一个get方法
app.get=function(string,callback){
if(!string.endsWith('/')){
string=string+'/';
}
if(!string.startsWith('/')){
string='/'+string;
}
// /login/
G[string]=callback;
//注册方法
//G['login']=function(req,res){
//
//}
}
//只有有请求 就会触发app这个方法
http.createServer(app).listen(3000);
//注册login这个路由(方法)
app.get('login',function(req,res){
console.log('login');
res.end('login');
})
app.get('register',function(req,res){
console.log('register');
res.end('register');
})
我们来看app方法:
//定义方法开始结束
var app=function(req,res){
//console.log('app'+req);
var pathname=url.parse(req.url).pathname;
if(!pathname.endsWith('/')){
pathname=pathname+'/';
}
if(G[pathname]){
G[pathname](req,res); /*执行注册的方法*/
}else{
res.end('no router');
}
}
这次我们获取了请求request的url,然后解析获取了请求的pathname,根据pathname去找注册了的路由。
get方法还是和之前的类似:
//定义一个get方法
app.get=function(string,callback){
if(!string.endsWith('/')){
string=string+'/';
}
if(!string.startsWith('/')){
string='/'+string;
}
// /login/
G[string]=callback;
//注册方法
//G['login']=function(req,res){
//
//}
}
然后我们注册了两个路由方法:
//注册login这个路由(方法)
app.get('login',function(req,res){
console.log('login');
res.end('login');
})
app.get('register',function(req,res){
console.log('register');
res.end('register');
})
接下来就是创建一个Server:
//只有有请求 就会触发app这个方法
http.createServer(app).listen(3000);
上面的代码相当于:
http.createServer(function(req,res){
//console.log('app'+req);
var pathname=url.parse(req.url).pathname;
if(!pathname.endsWith('/')){
pathname=pathname+'/';
}
if(G[pathname]){
G[pathname](req,res); /*执行注册的方法*/
}else{
res.end('no router');
}
}).listen(3000);
好了,我们的目标基本实现了,现在我们需要再进一步封装我们的代码,把一些代码提出来封装成一个模块。
我们把它封装成为express-route.js
var url=require('url');
//封装方法改变res 绑定res.send()
function changeRes(res){
res.send=function(data){
res.writeHead(200,{"Content-Type":"text/html;charset='utf-8'"});
res.end(data);
}
}
//暴露的模块
var Server=function(){
var G=this; /*全局变量*/
//处理get和post请求
this._get={};
this._post={};
var app=function(req,res){
changeRes(res);
//获取路由
var pathname=url.parse(req.url).pathname;
if(!pathname.endsWith('/')){
pathname=pathname+'/';
}
//获取请求的方式 get post
var method=req.method.toLowerCase();
if(G['_'+method][pathname]){
if(method=='post'){ /*执行post请求*/
var postStr='';
req.on('data',function(chunk){
postStr+=chunk;
})
req.on('end',function(err,chunk) {
req.body=postStr; /*表示拿到post的值*/
//G._post['dologin'](req,res)
G['_'+method][pathname](req,res); /*执行方法*/
})
}else{ /*执行get请求*/
G['_'+method][pathname](req,res); /*执行方法*/
}
}else{
res.end('no router');
}
}
app.get=function(string,callback){
if(!string.endsWith('/')){
string=string+'/';
}
if(!string.startsWith('/')){
string='/'+string;
}
// /login/
G._get[string]=callback;
}
app.post=function(string,callback){
if(!string.endsWith('/')){
string=string+'/';
}
if(!string.startsWith('/')){
string='/'+string;
}
// /login/
G._post[string]=callback;
//G._post['dologin']=function(req,res){
//
//}
}
return app;
}
module.exports=Server();
主程序:
var http=require('http');
var ejs=require('ejs');
var app=require('./model/express-route.js');
console.log(app);
http.createServer(app).listen(3000);
app.get('/',function(req,res){
var msg='这是数据库的数据'
ejs.renderFile('views/index.ejs',{msg:msg},function(err,data){
res.send(data);
})
})
//登录页面
app.get('/login',function(req,res){
console.log('login');
ejs.renderFile('views/form.ejs',{},function(err,data){
res.send(data);
})
})
//执行登录
app.post('/dologin',function(req,res){
console.log(req.body); /*获取post传过来的数据*/
res.send("<script>alert('登录成功');history.back();</script>")
})
app.get('/register',function(req,res){
console.log('register');
res.send('register');
})
app.get('/news',function(req,res){
console.log('register');
res.send('新闻数据');
})
好了我们自己的express也封装好了,通过上面的我们可以更加容易地理解express框架了。