在Node.js中实现Express(2)

在Node.js中实现Express(1):https://blog.csdn.net/qq_39263663/article/details/80480990

    Express提供的大部分功能是通过中间件函数完成的,这些中间件函数在Node.js收到请求的时点和发送响应的时点之间执行。Express的connect模块提供了中间间框架,可让你方便得在全局或路径级别或为单个路由插入中间件功能。

    通过Express支持的中间件可以让你快速提供静态文件,实现cookie,支持会话,处理post数据,等等,你甚至可以创建自己的自定义中间函数,并利用它们来预处理请求和提供自己的功能。

1,了解中间件

    Express提供了一个简单而有效的中间件框架,它允许你在接收到请求的时点及你真正处理请求和发送响应的时点之间提供附加功能。中间件可以应用身份验证,cookie和会话,并且在请求被传递给一个处理程序之前,以其他方式处理它。

    Express建立在connect NPM模块之上,提供了connect所提供的底层中间件支持。下面是一些由Express支持的中间件组件。

  • static:允许Express服务器以流式处理静态文件的GET请求。这个中间件是Express内置的,它可以通过express.static()访问。
  • express_logger:实现一个格式化的请求记录服务器来跟踪第服务器的请求。
  • basic-auth-connect:提供对基本的HTTP身份验证的支持。
  • cookie-parser:你可以从请求读取cookie并在响应中设置cookie
  • cookie-session:提供基于cookie的会话支持
  • express-session:提供了一个相当强大的会话实现。
  • body-parser:把POST请求正文中的JSON数据解析为req.body属性。
  • compression:对发给客户端的大响应提供Gzip压缩支持
  • csurf:提供站点请求伪造保护。

    要执行上述的功能,需要先安装相应的模块,如下:

npm install basic-auth-connect
npm install body-parser
npm install connect-mongo
npm install cookie-parser
npm install cookie-session
npm install express-session

    你还可以把express添加到package.json模块,以确保你部署应用程序的时候,这些模块被安装。


    你既可以对特点路径下的所有路由全局地应用中间件,也可以对一个特定的路由应用中间件。一下介绍这些方法。

1.1,在全局范围内把中间件分配给某个路径

    要对所有路由指定中间件,可以在Express app对象上实现use()方法。use()方法的语法如下:

use([path],middleware)

    path变量是可选的,默认为/,这意味着所有的路径。middleware参数是一个函数,它的语法如下,其中req是Request对象,res是Response对象,next是要执行的下一个中间件函数:

function(req,res,next)

    每个中间件组件都有一个构造函数,它返回相应的中间件功能。例如,要使用默认参数把body-parser中间件应用于所有路径,可以使用下面的语句:

var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use('/',bodyParser());
1.2,把中间件分配到单个路由

    你也可以通过把一个单独的路由放在path参数后来对应用body-parser中间件。例如,下面的代码,对/parsedRoute的请求将被记录,但对/otherRoute的请求不会被记录:

var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.get('/parserRoute',bodyParser(),function(req,res){
	res.send('this request was logged.');
});
app.get('/otherRoute',function(req,res){
	res.send('This resquest was not logged');
});
1.3,添加多个中间件函数

    你可以根据需要在全局范围和路由上分配任意多的中间件函数。例如下面的代码 

var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var app = express();
app.use('/',bodyParser()).
use('/',cookieParser()).
use('/',session());

2,使用query中间件

    最有用和最简单的中间件组件之一是query中间件。query中间件将一个查询字符串从URL转换为JavaScript对象,并将其保存为Request对象的query属性。从Express4.x开始,此功能在内置请求解析器中存在,而不需要额外的中间件。

    下面的代码片段显示了利用query中间件的基本方法:

var express = require('express');
var app = express();
app.get('/',function(req,res){
	var id = req.query.id;
	var score = req.query.score;
	console.log(JSON.stringify(req.query));
	res.send("done");
});

3,提供静态文件服务

    static中间件是很常用的Express中间件。static中间件可以让你直接从磁盘对客户端提供金泰文件服务。你可以使用static中间件支持不会改变的JavaScript文件,CSS文件,图像文件和HTML文件之类的东西。static模块非常容易实现,它使用一下语法:

express.static(path,[options])

    path 参数指定将在请求中引用的静态文件所在的根路径。options参数允许你设置以下属性。

  • maxAge:浏览器缓存maxAge(最长保存时间),以毫秒为单位。默认为0
  • hidden:如果为true,则表示启用隐藏文件传输功能。默认为false
  • redirect:如过为true,表示若请求路径是个目录,则该请求将被重定向到一个尾随/的路径,默认为true
  • index:根路径的默认文件名。默认为index.html

    下面的清单显示Express,Html和CSS代码来实现用来支持静态HTML。

express_static.js
var express = require('express');
var app = express();
app.use('/',express.static('./static'));
app.use('/images',express.static('../images'));
app.listen(80);
.static/index.html
<html>
	<head>
		<title>Static File</title>
		<link rel= "stylesheet" type="text/css" href="css/static.css">
	</head>
	<body>
		<img src="/images/heart.jpg" height="200px"/>
		<img src="/images/katon.jpg" height="200px"/>
		<img src="/images/little_man.png" height="200px"/>
	</body>
</html>
./static/css/static.css
img
{
	display:inline;
	margin:3px;
	border:5px solid #000000;
}


4,处理POST正文数据

    Express中间件的另一个非常常见的用途是处理POST请求正文中的数据。请求正文内的数据可以是各种格式,如post参数字符串,JSON字符串,或原始数据。Express的body-parser中间件视图解析请求的正文中的JSON数据,把他们正确地格式化为Request对象的req.body属性。

    例如,如果该中间件接收post参数或JSON数据,就把他们转换为JavaScript对象,并将它作为Resquest对象的req.body属性存储、下面的清单说明了使用body-parser中间件来支持发布到服务器的表单数据。

var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser());
app.get('/',function(req,res){
	var response = '<form method="post">' +
		'First:<input type="text" name="first"><br>' + 
		'Last:<input type="text" name="last"><br>' +
		'<input type="submit" value="Submit"></form>';
	res.send(response);
});
app.post('/',function(req,res){
	var response = '<form method="POST">' + 
		'First:<input type="text" name="first"><br>' + 
		'Last:<input type="text" name="last"><br>' + 
		'<input type="submit" value="Submit"></form>' +
		'<h1>Hello ' + req.body.last + '</h1>';
		res.type('html');
		res.end(response);
		console.log(res.body);
});
app.listen(80);

5,发送和接收cookie

    Express提供的cookie-parser中间件使得处理cookie非常简单。该cookie-parser中间件从一个请求解析cookie,并将它们作为一个JavaScript对象存储在req.cookie属性中。cookie-parser中间件使用一下语法:

express.cookie-parser([secret])

    可选的secret字符串参数利用secret字符串在cookie内部签署来防止cookie的篡改。

    要在响应中设置cookie,你可以使用如下所示的res.cookie()方法:

res.cookie(name,value,[options])

    具有指定的名称和值参数的一个cookie被添加到响应中。options参数允许你设置cookie中的以下属性。

  • maxAge:一毫秒为单位的时间量,表示cookie过期前的生存时间。
  • httpOnly:如果为true,则表示这个cookie只能由服务器访问;而不能通过客户端JavaScript访问。
  • signed:如果问哦true,表示该cookie将被签署;你需要使用req.signedCookie对象,而不是req.cookie对象来访问它。
  • path:该cookie应用的路径。

    例如,下面的语句设置一个hasVisited cookie:

res.cookie('hasVisited','1',
	{maxAge:60*60*1000,
	httpOnly:true,
	path:'/'});

    你可以从客户端利用res.clearCookie()方法删除cookie。例如:

res.clearCookie('hasVisited');

    下面的清单显示了一个简单的例子,它从请求得到一个名为req.cookies.hasVisited的cookie;并且如果它尚未设置,就设置它。

var express = require('express');
var cookieParser = require('cookie-parser');
var app = express();
app.use(cookieParser());
app.get('/',function(req,res){
	console.log(req.cookies);
	if(!req.cookies.hasVisited){
		res.cookie('hasVisited','1',
			{maxAge:60*60*1000,
			httpOnly:true,
			path:'/'});
	}
	res.send("Sending Cookie");
});
app.listen(80);

6,实现会话

    Express中间件另一种非常常见的用途是为应用程序提供会话支持。对于复杂的会话管理,你可能想要自己实现它;但是对于基本的会话支持,cookie-session中间件的工作效果已经比较好了。

    cookie-session会话中间件在底层利用cookie-parser中间件,所以你需要在添加cookie-session前添加cookie-parser。下面显示了添加cookie-session中间件的语法:

res.cookie([options])

    options参数允许你设置cookie中的以下属性。

  • key:用于标识会话的cookie名称
  • secret:用来签署会话cookie的字符串。它用来防止cookie窃取
  • cookie:一个对象,它定义了cookie的设置,包括maxAge,path,httpOnly和signed。默认值是{path:'/',httpOnly:true,maxAge:null}.
  • proxy:一个布尔值,如果为true,将导致Express通过x-forwarded-proto设置安全cookie时,信任反向代理。

   当cookie-session被实现时,会话被存储为req.session对象。你对req.session做的任何更改都会跨越来自同一个浏览器的多个请求流动。

    下面的代码清单显示了实现基本的cookie-session会话的例子。

var express = require('express');
var cookieParser = require('cookie-parser');
var cookieSession = require('cookie-session');
var app = express();
app.use(cookieParser());
app.use(cookieSession({secret:'MAGICALEXPRESSKEY'}));
app.get('/library',function(req,res){
	console.log(req.cookies);
	if(req.session.restricted){
		res.send('You have been in the restricted section ' +
			req.session.restrictedCount + ' times. ');
	}else{
		res.send('Welcome to the library.');
	}
});
app.get('/restricted',function(req,res){
	req.session.restricted = true;
	if(!req.session.restrictedCount){
		req.session.restrictedCount = 1;
	}else{
		req.session.restrictedCount +=  1;
	}
	res.redirect('/library');
});
app.listen(80);

7,应用基本的HTTP身份验证

    Express中间件的另一个常见用途是应用基本的HTTP身份验证。HTTP身份验证室友Authorization标头从浏览器想服务器发送编码后的用户名和密码。如果在浏览器中没有存储URL的授权信息,浏览器会启动一个基本的登录对话框,让用户名输入用户名和密码。基本的HTTP身份验证很适合那些需要最低限度身份验证方法的基本网站,并且很容易实现。

    Express的basic-auth-connect中间件函数提供对处理基本的HTTP身份验证的支持。basic-auth-connect中间件使用以下语法:

var basicAuth = require('basic-auth-connect');
express.basicAuth(function(user,pass){})

    传递到basic-auth-connect的函数接收用户名和密码。然后如果它们是正确的,则返回true;如果错误,则返回false。例如:

app.use(express.basicAuth(function(user,password){
	return(user === 'testuser' && pass === 'test');
}));

    通常情况下你在数据库中存储用户名和密码,然后在authentication函数中检索要验证的用户对象。

    下面的代码清单说明了实现basic-auth-connect中间件是多么容易。第一个清单实现了一个全局性的验证。第二个清单对路由出现了身份验证。

                                        为网站在全局范围内实现基本的HTTP身份验证

var express = require('express');
var basicAuth = require('basic-auth-connect');
var app = express();
app.listen(80);
app.use(basicAuth(function(user,pass){
	return(user === 'xiaobaicai' && pass === 'xiaobaicai');
}));
app.get('/',function(req,res){
	res.send('Successful Authedtication!');
});

                                          为一个单独的路由实现基本的HTTP身份验证

var express = require('express');
var basicAuth = require('basic-auth-connect');
var app = express();
var auth = basicAuth(function(user,pass){
	return(user === 'xiaobaicai1' && pass === 'xiaobaicai2' );
});
app.get('/library',function(req,res){
	res.send('Welcome to the library');
});
app.get('/restricted',auth,function(req,res){
	res.send('Welcome to the restricted section.');
});
app.listen(80);


8,实现会话身份验证

    基本HTTP身份验证的一个主要缺点是,只要证书被存储,登录就一直存在,这不是很安全。一个更好的方法是,实现自己的身份验证机制,并将其存储在一个你可以随时使之过期的会话中。

    Express内的session中间件对于实现会话的验证效果都非常好。session中间件附加一个Session对象req.session到Request对象来提供会话功能。下表描述了你可以在res.session对象上调用的方法。

res.session对象上用来管理会话的方法
方法 说明
regenerate([callback]) 移除并创建一个新的req.session对象,让你重置会话
destory([callback]) 移除req.session对象
save([callback]) 保存会话数据

touch([callback])

为会话cookie重置maxAge计数
cookie 指定把会话链接到浏览器的cookie对象
    下面的代码清单显示了如何使用crypto模块生成安全的密码来实现会话验证。这个例子是非常简陋的,但它包含了基本的功能,所以你可以看到如何实现会话验证。
function hashPW(pwd){
	return crypto.createHash('sha256').update(pwd).
		digest('base64').toString();
}
var app = express();
app.use(bodyParser());
app.use(cookieParser('MAGICString'));
app.use(session());
app.get('/restricted',function(req,res){
	if(req.session.user){
		res.send('<h2>' + req.session.success +'</h2>' + 
				 '<p>You have entered the restricted section<p><br>' + 
				 '<a href="/logout">logout</a>');
	}else{
		req.session.error = 'Access denied!';
		res.redirect('/login');
	}
});
app.get('/login',function(req,res){
	var response = '<from method="POST">' +
		'Username: <input type = "text" name ="username"><br>' + 
		'Password: <input type="password" name="password"><br>' +
		'<input type="submit" value="Submit"></form>';
		if(req.session.user){
			res.redirect('/restricted');
		}else if(req.session.error){
			response += '<h2>' + req.session.error +'<h2>';
		}
		res.type('html');
		res.send(response);
});
app.post('/login',function(req,res){
	//user should be a lookup of req.body.username in database
	var user = {name:req.body.username,password:hashPW("myPass")};
	if(user.password === hashPW(req.body.password.toString())){
		req.session.regenerate(function(){
			req.session.user = user;
			req.session.success = 'Authenticated as' + user.name;
			res.redirect('/redirected');
		});
	}else{
		req.session.regenerate(function(){
			req.session.error = 'Authentication failed.';
			res.redirect('/redirected');
		});
		res.redirect('/login');
	}
});
app.listen(80);

9,创建自定义中间件

    使用Express,你可以创建自己的中间件。你需要做的所有工作就是提供一个接受Request对象作为第一个参数,Response对象作为第二个参数,next作为第三个参数的函数。next参数是一个通过中间件框架传递的函数,它指向下一个要执行的中间件函数,所以你必须在退出自定义函数之前调用next();否则处理程序将永远不会被调用。

    下面的代码清单实现了一个名为queryRemover()的中间件函数,这个函数在把查询字符串发送到处理程序之前把该字符串从URL中剥离。

var express = require('express');
var app = express();
function queryRemover(req,res,next){
	console.log("\nBefore URL:");
	console.log(req.url);
	req.url = req.url.split('?')[0];
	console.log("\nAfter URL: ");
	console.log(req.url);
	next();
};
app.use(queryRemover);
app.get('/no/query',function(req,res){
	res.send("test");
});
app.listen(80);

猜你喜欢

转载自blog.csdn.net/qq_39263663/article/details/80498260