您的位置:首页 > Web前端 > Node.js

Nodejs Express 开发必备知识点

2015-11-19 20:34 796 查看

npm 常用指令

npm install <name> 安装Node.js依赖包例如npm install express 就会默认安装express的最新版本,也可以通过在后面加版本号的方式安装指定版本,如npm install express@3.0.6npm install <name> -g 将包安装到全局环境中但是代码中,直接通过require()的方式是没有办法调用全局安装的包的。全局的安装是供命令行使用的,就好像全局安装了vmarket后,就可以在命令行中直接运行vm命令npm install <name> --save 安装的同时,将信息写入package.json中项目路径中如果有package.json文件时,直接使用npm install方法就可以根据dependencies配置安装所有的依赖包,所以移交项目时不用吧node_modules文件一起了这样代码提交到github时,就不用提交node_modules这个文件夹了。npm init 会引导你创建一个package.json文件,包括名称、版本、作者这些信息等npm remove <name>移除npm update <name>更新npm ls 列出当前安装的了所有包npm root 查看当前包的安装路径npm root -g 查看全局的包的安装路径npm help 帮助,如果要单独查看install命令的帮助,可以使用的npm help install使用npm init 指令会生成一个package.json,如下所示。然后执行 npm install --save express 后package.json文件中的dependencies字段发生变更
{
"name": "easy_express",
"version": "0.1.0",
"description": "my express test",
"main": "index.js",
"scripts": {
"test": "make test"
},
"keywords": [
"node",
"esay"
],
"author": "feng",
"license": "MIT",
"dependencies": {.
"express": "^4.13.3"
}
}

如何设置静态资源

express.static是Express内置的唯一一个中间件,负责托管express应用内的静态资源。它可以将一个或多个目录指派为包含静态资源的目录,其中的资源不经任何特殊处理直接发送给客户端(如css文件、js文件等)。因为这个目录完全开放,所以我们一般设置这个静态资源文件夹为public
app.use(express.static(__dirname + '/public'));
接下来我们在public下面创建一个子目录Img,并把logo.png放到其中,现在我们可以直接指向/img/logo.png(注意路径中并没有public,这个目录对客户端来说是隐形的),static中间件会返回这个文件,并正确设定内容类型
<img src="/img/logo.png"
或者干脆在浏览器里这么访问
http://localhost:3000/images/kitten.jpg

Express中请求对象request、response的属性和方法

req.params:·一个数组,包含命名过的路由参数· app.get('/student/:name',function(req,res){ var name = req.params.name}); 路由中使用了:name,他会跟任何字符串匹配(不包括反斜杠),并将其跟键name一起放到req,params对象中
前端页面拼接请求字符串:url = '/apple/detail/'+code+'/'+miniCode;设置路由:              app.get('/apple/detail/:code/:miniCode', controller.product.p2pMiniDetail);在对应的p2pMiniDetail中读取参数:    var code = req.params.code;  var miniCode = req.params.miniCode;
req.query`一个对象,包含以键值对存放的查询字符串(通常称为GET请求参数)
前端页面拼接请求字符串:url = '/apple/detail/'+'?uid='+uid+'&kind='+kind;设置路由:              app.get('/apple/detail/', controller.product.p2pMiniDetail);在对应的p2pMiniDetail中读取参数:    var uid = req.query.uid;  var kind = req.params.kind;
req.body`一个对象,包含POST请求参数(一般用于解析表单中的值,需要中间件能够解析请求内容类型)req.cookies`一个对象,包含从客户端传递过来的cookies值req.headers`从客户端接收到的请求报头req.ip`客户端的IP地址req.path/req.host/req.protocol/`请求路径(不包含协议、主机、端口或查询字符串)/返回客户端报告的主机名(这些信息可以伪造,所以不应该用于安全目的)/协议req.xhr`一个简便属性,如果请求有Ajax发起将会返回truereq.url/req.originalUrl`返回路径和查询字符串(不包含协议、主机、端口)res.status(code)`设置HTTP状态代码,如 function(req,res){ res.status(404.render('not-found'))}res.cookie(name,value,[options])/res.clearCookie(name,[options])`设置或者清楚客户端cookies值,需要中间件支持res.redirect([status],url)`重定向浏览器,默认重定向代码是302。通常你经过该尽量减少重定向,除非永久移动一个页面,这时候状态码301res.send(body)/res.send(status,body)·向客户端发送响应及可选状态码,如果body是一个对象或者一个数组,响应将会以JSON发送(这种情况为什么不使用res.json呢?)res.json(status)/res.json(status,json)·向客户端发送JSON以及可选的状态码res.sendFile(path,[option],[callback])·这个方法根据路径读取指定文件并将内容发送到客户端res.locals,render(view,[locals],callback)·res.locals是一个对象,包含用于渲染视图的默认上下文。· res.render使用配置的模板引擎渲染视图,默认响应码为200
app.get('/',function(req,res){res.render('index',{message:'welcome',style:req.query.style,userid:req.cookie.userid})})
在静态页面中(以ejs模板引擎为例)使用<%= message%>输出welcome。render中的第二个参数就是所谓的context(上下文环境),当你渲染一个模板(静态页面如html格式),便会传递给模板引擎一个对象,叫做上下文对象,它能让替换标志运行。刚才我们就是用上下文对象中的message对象的值替换掉<%= message%>中的占位符,从而实现了前台页面上的动态数据的渲染

Exports&&module.exports

Nodejs使用exports和module.exports来完成功能的组织及重用。Nodejs模块允许你从被引入文件中选择要暴漏给程序的函数和变量。如果模块返回的函数或变量不止一个,那他可以通过设定exports对象的属性来指明他们;但如果模块只返回一个函数或变量,则可以设定module.exports属性。这样做可以选择把什么跟程序共享而不污染全局命名空间。在moduleName.js文件内使用exports.something = function(){}类似的代码将函数导出,然后在目标文件内引入模块的该函数:var muModule = require('moduleName.js') muModule.somthing();//可以用exports导出多个函数但是如果只是想用exports导出一个变量或函数,你可能会以为只要把exports设定成你想要的东西就行。但是这样是不行的,因为Node觉得不能用任何其他对象、函数或变量给exprts赋值。例如不能使用exports = something;应该用module.exports替换掉exports。用module.exports可以对外提供单个变量、函数或对象。如果创建了一个既有exports又有module.exports的模块,那么他会返回module.exports而exports则会被忽略记住三点:1.exxports是指向module.exports的引用,module.exports初始值为一个空对象,所以exports的值也为{},所以exports.myFun只是module.exports.myFun的简写2.当我们想让模块道出的是一个对象时,exports和module.exports都可以用;而当我们导出非对象接口时,就必须也只能覆盖module.exports3.如果把exports设置为别的,就打破了module.exports和exports之间的引用关系。那样exports就不能用了,因为他不在指向module.exports。如果想维持链接,需要让module.exports再指向exports:module.exports = exports创建模块系统的注意事项第一:如果模块是目录,在模块目录中定义的模块的文件必须命名为index.js,除非你在这个目录下一个叫package.json的文件里特别说明(其中一个名为main的键)第二:Node能把模块作为对象缓存起来-》“猴子补丁”

表单处理

 <form action="/process" method="post"><input type="hidden" name="hush" val="hidden,but not secret !"><div><label for="fieldColor"> Your favorite color:</label><input type="text" id="fieldColor" name="color"></div><div><button type="submit">Submit</button></div></form>
1.大体上来讲,向服务器端发送客户端数据分为两种方式:查询字符串(GET请求)和请求正文(POST请求),有一种普遍的误解是POST请求是安全的,而GET请求是不安全的。事实上,如果使用HTTPS协议两者都是安全的;如果不使用,则都不安全,因为这是入侵者会想查看GET请求的查询字符串一样轻松查看POST请求的报文数据。2.从服务器的角度来看,最重要的属性是<input>域中的name属性,这样服务期才能识别字段。name属性与id属性时截然不同的,后者只适用于样式和前端功能(他并不会发送到服务器端),理解这一点非常重要。3.隐藏域:他不会出现在浏览器中,但是你不能使用他存放秘密和敏感信息,一旦用户审查源文件就会暴漏隐藏域。4.使用post提交表单,需要引入中间件来解析URL编码体。安装:npm install --save body-parser引入:app.use(require('body-parser')());一旦引入了body-parser,req.body变为可用,这样所有的表单字段都可用
  app.post('/process',function(req,res){console.log('color from filed : '+ req.body.color);res.redirect('303','/thank-you')})
5.上传文件:使用Formidable模块(Express4.0开始不支持Connect的内置中间件multipart)安装:npm install --save formidable引用:var formidable = require('formidable')路由:
     app.post('/contest/photos',function(req,res){var form = new formidable.IncomingForm();form.parse(req,function(err,fields,files){if(err) return res.redirect(303,'/error');console.log('recieved fields: ');console.log(fields);console.log('received files');console.log(files);res.redirect(303,'/thank-you')});})
HTML
<form enctype="multipart/form-data" method="POST" action="/contest/photos"><input type="file" required accept="image/*" name="photo"></form>

Express中的cookie

安装模块:npm install --save cookie-parser引入中间件:var cookieParser = require('cookie-parser'); app.use(cookieParser('some strings here'));在任何能够访问到响应对象的地方设置cookie:res.cookie('monster','feng');获得客户端传过来的cookie值:var monster = req.cookie.monster;删除cookie:res.clearCookie('monster');可以使用如下方法给cookie定值属性:cookieOptions:{maxAge: 86400 * 30,domain:'.google.com'path:''}function setCookie(res, key, value){res.cookie(key, value, cookieOptions);}setCookie(res, 'userName', user.userName);注:设置cookie的时候可以使用如下这些选项domain:控制跟cookie关联的域名,这样你可以将cookie分配给特定的子域名。但是你不能给cookie设置根服务器所用域名不同的域名,因为那样做它什么也不会做。maxAge: 指定客户端应该保存cookie多长时间,毫秒单位。如果忽略这一项浏览器会在关闭时自动将cookie删掉secure:指定cookie只能通过https连接发送httpOnly:将这个选项设置为true表明这个cookie只能由服务器端修改,也就是说客户端Javascript不能修改它,有助于防范XSS攻击。

中间件

从功能上讲,中间件是一种功能的封装方式,具体来说就是封装在程序中处理HTTP请求功能。它是在管道中执行的,可以想象一个送水的真实管道。水从一端泵入,然后到达目的地之前还会经过仪表和阀门。这个比喻中很重要的一部分是顺序问题,你把压力表放到阀门之前和之后会有不同的效果。同样,如果你有个向水中注入什么东西的阀门,那么这个阀门“下游”的所有东西都会含有这个新添加的原料。在Express程序中,通过调用app.use向管道中插入中间件。在Express 4.0中,中间件和路由器是按照他们的连入顺序调用的,顺序更清晰。在管道的最后放一个“捕获一切”请求的处理器是常见的做法,用他来处理跟前面其他所有的路又都不匹配的请求,这个请求一般会返回状态码404。同时在这个中间件之后,还应该存在一个用来捕获所有uncaughtException的中间件,用来处理所有为捕获错误(包括上一个中间件发出的404error、静态页面数据错误、undefined引用等,注意when.js中的then{}不会被捕捉)
//拦截所有未匹配路由的请求,如果请求流到了这里,则创建一个404状态的error,next(err)给下一个中间件app.use(function(req, res, next) {var err = new Error('Not Found');err.status = 404;next(err);});//这个中间件可以处理err请求,捕捉然后按照不同的环境处理if (app.get('env') === 'dev' || app.get('env') === 'staging') {app.use(function(err, req, res, next) {res.render('error_dev', {message: err.message,error: err});});}else {app.use(function(err, req, res, next) {res.render('error');});}
那么请求在管道中如何终止呢?这是又传给每个中间件的next函数来实现的如果不调用next(),请求就在那个中间件中终止了。这个时候你应该发送一个响应到客户端(res.send、res.json、res.render),如果你不这样做,客户端会被挂起并最终导致超时;切切相反,如果调用了next(),一般不宜在发送响应到客户端了。如果你发送了,管道中后续的中间件火炉有处理器还会执行,但是他们发送的任何响应都会被被忽略。模块可以输出一个以中间件为属性的对象,这个中间件可以放到正常的路由调用中,作为其中的几个阀门,如果不满足中间件要求,这个路由调用就会不通过在controller/user.js中导出一个判断检查登录状态的中间件
module.exports = {/*** 登陆状态检查*/authorize: function (req, res, next) {if (!req.cookies.userId) {res.redirect('/user/login');} else {next();}}}
当用户点击个人资产按钮时,进行身份验证
app.get('/assets', controller.user.authorize, controller.assets.index);
用户请求/assets路径,首先调用user.authorize验证是否登陆,已登录则next()反之则重定向到/user/login路由常用中间件:1)body-parser:略;2)cookie-parser:略;3)cookie-session:放到cookie-parser后面一起使用,提供cookie存储的会话支持4)static: app.use(express.static(path.join(__dirname, 'public')));提供对静态文件的支持,可以连入多次,并可指定不同的目录。

开发与部署

·Nodejs支持执行环境的概念,这里笔者建议你使用标准的开发、生产和测试环境。·使用环境变量NODE_ENV来设置,可以在两个地方,一个是在系统的环境变量中,如果是在windows系统下,则在系统环境变量中添加一组选项NODE_ENV 值设置为dev/production/staging中的一种,这样做每次开启命令行执行程序时都会自动运行该环境变量的程序;第二种是在运行代码的同时设置环境变量,set NODE_ENV=dev/staging/production 回车 node bin/www,这样做每次都需要设置环境你变量。·你可以使用app.get('env')来获取当前的环境变量用应用集群扩展:Nodejs本身支持因攻击群,踏实一种简单的、单服务器形式的向外扩展。使用应用集群,你可以为系统的每个CPU创建一个独立的服务器,我们在bin目录下创建一个www文件,作为启动文件
var app = require('../app');var cluster = require('cluster');var numCPUs = require('os').cpus().length;if (cluster.isMaster) {// Fork workers.for (var i = 0; i < numCPUs; i++) {cluster.fork();}cluster.on('exit', function(worker, code, signal) {console.log('worker ' + worker.process.pid + ' died');});} else {// Workers can share any TCP connection,in this case its a HTTP serverapp.set('port', process.env.NODE_PORT || 9099 );var server = app.listen(app.get('port'), function() {console.log('Express server listening on port ' + server.address().port);});}
这样你只需执行node bin/www,nodejs就会为你当前系统的每一个内核开启一个线程,充分利用当前服务器的硬件资源,

送上 express 4.x中文API地址,供大家参考:http://www.expressjs.com.cn/4x/api.html#res

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: