Express 是一个小巧且灵活的 Node.js Web应用框架,它有一套健壮的特性,可用于开发单页、多页和混合Web应用。css
npm安装html
$ npm install express
建立http服务linux
//引入express var express = require('express'); //执行express**函数 var app = express(); //监听端口 app.listen(3000);
根据请求路径来处理客户端发出的GET请求git
第一个参数path为请求的路径github
第二个参数为处理请求的回调函数shell
app.get(path,function(req, res));
get方法使用:express
//引入express var express = require('./express'); //执行express函数 var app = express(); //监听端口 app.get('/hello', function (req,res) { res.end('hello'); }); app.get('/world', function (req,res) { res.end('world'); }); app.get('*', function (req,res) { res.setHeader('content-type','text/plain;charset=utf8'); res.end('没有找到匹配的路径'); }); app.listen(3000);
get方法实现:npm
//声明express函数 var express = function () { var app = function (req,res) { var urlObj = require('url').parse(req.url,true); var pathname = urlObj.pathname; var method = req.method.toLowerCase(); //找到匹配的路由 var route = app.routes.find(function (item) { return item.path==pathname&&item.method==method; }); if(route){ route.fn(req,res); } res.end(`CANNOT ${method} ${pathname}`) }; //增长监听方法 app.listen = function (port) { require('http').createServer(app).listen(port); }; app.routes = []; //增长get方法 app.get = function (path,fn) { app.routes.push({method:'get',path:path,fn:fn}); }; return app; }; module.exports = express;
使用 * 匹配全部路径:json
var route = app.routes.find(function (item) { - return item.path==pathname&&item.method==method; + return (item.path==pathname||item.path=='*')&&item.method==method; });
根据请求路径来处理客户端发出的POST请求数组
第一个参数path为请求的路径
第二个参数为处理请求的回调函数
app.post(path,function(req,res));
post方法的使用:
//引入express var express = require('./express'); //执行express函数 var app = express(); //监听端口 app.post('/hello', function (req,res) { res.end('hello'); }); app.post('*', function (req,res) { res.end('post没找到'); }); app.listen(3000);
经过linux命令发送post请求
$ curl -X POST http://localhost:3000/hello
post的实现:
增长全部请求的方法
var methods = ['get','post','delete','put','options']; methods.forEach(function (method) { app[method] = function (path,fn) { app.routes.push({method:method,path:path,fn:fn}); }; });
监听全部的请求方法,能够匹配全部的HTTP动词。根据请求路径来处理客户端发出的全部请求
第一个参数path为请求的路径
第二个参数为处理请求的回调函数
app.all(path,function(req, res));
all的方法使用:
var express = require('./express'); var app = express(); app.all('/hello', function (req,res) { res.end('hello'); }); app.all('*', function (req,res) { res.end('没找到'); }); app.listen(3000);
注册全部方法:增长all方法匹配全部method
+ var methods = ['get','post','delete','put','options','all'];
all方法的实现:对all方法进行判断
var route = app.routes.find(function (item) { - return (item.path==pathname||item.path=='*')&&item.method==method; + return (item.path==pathname||item.path=='*')&&(item.method==method||method=='all'); });
中间件就是处理HTTP请求的函数,用来完成各类特定的任务,好比检查用户是否登陆、检测用户是否有权限访问等,它的特色是:
一个中间件处理完请求和响应能够把相应数据再传递给下一个中间件
回调函数的next参数,表示接受其余中间件的调用,函数体中的next(),表示将请求数据继续传递
能够根据路径来区分返回执行不一样的中间件
中间件的使用方法:
增长中间件
var express = require('express'); var app = express(); app.use(function (req,res,next) { console.log('过滤石头'); next(); }); app.use('/water', function (req,res,next) { console.log('过滤沙子'); next(); }); app.get('/water', function (req,res) { res.end('water'); }); app.listen(3000);
use方法的实现:在路由数组中增长中间件
app.use = function (path,fn) { if(typeof fn !='function'){ fn = path; path = '/'; } app.routes.push({method:'middle',path:path,fn:fn}); }
app方法中增长Middleware判断:
- var route = app.routes.find(function (item) { - return item.path==pathname&&item.method==method; - }); - if(route){ - route.fn(req,res); - } var index = 0; function next(){ if(index>=app.routes.length){ return res.end(`CANNOT ${method} ${pathname}`); } var route = app.routes[index++]; if(route.method == 'middle'){ if(route.path == '/'||pathname.startsWith(route.path+'/')|| pathname==route.path){ route.fn(req,res,next) }else{ next(); } }else{ if((route.path==pathname||route.path=='*')&&(route.method==method||route.method=='all')){ route.fn(req,res); }else{ next(); } } } next();
错误中间件:next中能够传递错误,默认执行错误中间件
var express = require('express'); var app = express(); app.use(function (req,res,next) { console.log('过滤石头'); next('stone is too big'); }); app.use('/water', function (req,res,next) { console.log('过滤沙子'); next(); }); app.get('/water', function (req,res) { res.end('water'); }); app.use(function (err,req,res,next) { console.log(err); res.end(err); }); app.listen(3000);
错误中间件的实现:对错误中间件进行处理
function next(err){ if(index>=app.routes.length){ return res.end(`CANNOT ${method} ${pathname}`); } var route = app.routes[index++]; + if(err){ + if(route.method == 'middle'&&route.fn.length==4){ + route.fn(err,req,res,next); + }else{ + next(err); + } + }else{ if(route.method == 'middle'){ if(route.path == '/'||pathname.startsWith(route.path+'/')|| pathname==route.path){ route.fn(req,res,next) }else{ next(); } }else{ if((route.path==pathname||route.path=='*')&&(route.method==method||route.method=='all')){ route.fn(req,res); }else{ next(); } } + } }
req.hostname
返回请求头里取的主机名
req.path
返回请求的URL的路径名
req.query
查询字符串
//http://localhost:3000/?a=1 app.get('/',function(req,res){ res.write(JSON.stringify(req.query)) res.end(req.hostname+" "+req.path); });
具体实现:对请求增长方法
+ req.path = pathname; + req.hostname = req.headers['host'].split(':')[0]; + req.query = urlObj.query;
req.params 匹配到的全部路径参数组成的对象
app.get('/water/:id/:name/home/:age', function (req,res) { console.log(req.params); res.end('water'); });
params实现:增长params属性
methods.forEach(function (method) { app[method] = function (path,fn) { var config = {method:method,path:path,fn:fn}; if(path.includes(":")){ //是路径参数 转换为正则 //而且增长params var arr = []; config.path = path.replace(/:([^\/]+)/g, function () { arr.push(arguments[1]); return '([^\/]+)'; }); config.params = arr; } app.routes.push(config); }; }); + if(route.params){ + var matchers = pathname.match(new RegExp(route.path)); + if(matchers){ + var params = {}; + for(var i = 0; i<route.params.length;i++){ + params[route.params[i]] = matchers[i+1]; + } + req.params = params; + route.fn(req,res); + }else{ + next(); + } +}else{ if((route.path==pathname||route.path=='*')&&(route.method==method||route.method=='all')){ route.fn(req,res); }else{ next(); } +}
参数为要响应的内容,能够智能处理不一样类型的数据,在输出响应时会自动进行一些设置,好比HEAD信息、HTTP缓存支持等等
res.send([body]);
当参数是一个字符串时,这个方法会设置Content-type为text/html
app.get('/', function (req,res) { res.send('<p>hello world</p>'); });
当参数是一个Array或者Object,这个方法返回json格式
app.get('/json', function (req,res) { res.send({obj:1}); }); app.get('/arr', function (req,res) { res.send([1,2,3]); });
当参数是一个number类型,这个方法返回对应的状态码短语
app.get('/status', function (req,res) { res.send(404); //not found //res.status(404).send('没有找到');设置短语 });
send方法的实现:自定义send方法
res.send = function (msg) { var type = typeof msg; if (type === 'string' || Buffer.isBuffer(msg)) { res.contentType('text/html').status(200).sendHeader().end(msg); } else if (type === 'object') { res.contentType('application/json').sendHeader().end(JSON.stringify(msg)); } else if (type === 'number') { res.contentType('text/plain').status(msg).sendHeader().end(_http_server.STATUS_CODES[msg]); } };
npm安装ejs
$ npm install ejs
使用ejs模版
var express = require('express'); var path = require('path'); var app = express(); app.set('view engine','ejs'); app.set('views',path.join(__dirname,'views')); app.listen(3000);
配置成html格式
app.set('view engine','html') app.set('views',path.join(__dirname,'views')); app.engine('html',require('ejs').__express);
第一个参数 要渲染的模板
第二个参数 渲染所须要的数据
app.get('/', function (req,res) { res.render('hello',{title:'hello'},function(err,data){}); });
读取模版渲染
res.render = function (name, data) { var viewEngine = engine.viewEngineList[engine.viewType]; if (viewEngine) { viewEngine(path.join(engine.viewsPath, name + '.' + engine.viewType), data, function (err, data) { if (err) { res.status(500).sendHeader().send('view engine failure' + err); } else { res.status(200).contentType('text/html').sendHeader().send(data); } }); } else { res.status(500).sendHeader().send('view engine failure'); } }
若是要在网页中加载静态文件(css、js、img),就须要另外指定一个存放静态文件的目录,当浏览器发出非HTML文件请求时,服务器端就会到这个目录下去寻找相关文件
var express = require('express'); var app = express(); var path = require('path'); app.use(express.static(path.join(__dirname,'public'))); app.listen(3000);
配置静态服务器
express.static = function (p) { return function (req, res, next) { var staticPath = path.join(p, req.path); var exists = fs.existsSync(staticPath); if (exists) { res.sendFile(staticPath); } else { next(); } } };
redirect方法容许网址的重定向,跳转到指定的url而且能够指定status,默认为302方式。
参数1 状态码(可选)
参数2 跳转的路径
res.redirect([status], url);
使用重定向
app.get('/', function (req,res) { res.redirect('http://www.baidu.com') });
302重定向
res.redirect = function (url) { res.status(302); res.headers('Location', url || '/'); res.sendHeader(); res.end(); };
安装body-parser
$ npm install body-parser
接收请求体中的数据
app.get('/login', function (req,res) { res.sendFile('./login.html',{root:__dirname}) }); app.post('/user', function (req,res) { console.log(req.body); res.send(req.body); }); app.listen(3000);
实现bodyParser
function bodyParser () { return function (req,res,next) { var result = ''; req.on('data', function (data) { result+=data; }); req.on('end', function () { try{ req.body = JSON.parse(result); }catch(e){ req.body = require('querystring').parse(result); } next(); }) } };