Express
Express提供了一个轻量级模块,把nodejs的http功能封装在一个简单易用的接口中。Express也扩展了http模块的功能,能轻松处理服务器的路由、响应、cookie和HTTP请求的状态。
一 安装和配置
1.全局安装
npm install -g express
输入express -h如果出现:
执行:npm install -g express-generator
我们可以查看express的版本,通过npm ls查看express和它的依赖的树形结构
2.Express的配置
express对象提供了set(setting,value)、enable(setting)和disable(setting)方法来为应用程序的设置来设定值。
如启用信任代理:app.enable('trust proxy');
一般能设置的有:
env 定义环境模式字符串,如development,testing,production,默认值是process.env.NODE_ENV
trust_proxy 启用/禁用反向代理的支持,默认为false
jsonp callback name 定义JSONP请求的默认回调名称。默认值是?callback=
json replacer 定义JSON replacer回调函数,默认为null
json spaces 指定当格式化JSON响应时使用的空格数量,默认在开发中为2,在生产为0
case sensitive routing 启用/禁用区分大小写,如/home与/Home是不一样的,默认为disabled
strict routing 启用/禁用严格的路由,如/home和/home/是不一样的,默认为disabled
view cache 启用/禁用视图模板编译缓存,默认为enabled
view engine 指定呈现模板时,如果从视图中省略了文件扩展名,应该使用的默认模板引擎扩展
views 指定模板引擎用来查找视图模板的路径,默认值是./views
二 启动express服务器
var express=require('express'); var app=express(); app.listen(8080);
注意,listen()方法调用底层的HTTP连接绑定到port上,并开始监听它。事实上,express()返回的值实际上是一个回调函数,它映射了传递到http.createServer()和https.createServer()方法的回调函数。
用express实现HTTP和HTTPS服务器
var express=require('express'); var https=require('https'); var http=require('http'); var fs=require('fs'); var options={ host:'127.0.0.1', key:fs.readFileSync('ssl/server.key'), cert:fs.readFileSync('ssl/server.crt') }; http.createServer(app).listen(80); https.createServer(options,app).listen(443); app.get('/',function(req,res){ res.send('Hello, Express'); });
一个典型的使用express的app.js,主要做了以下几件事:
(1)导入相关模块
(2)执行过var app=express()后,
使用app.set设置express内部的一些参数(options)
使用app.use来注册函数
通过http.createServer用app来处理请求
实 际上,express通过app.use注册middleware,middleware相当于request的handlers,在处理request 时,顺序执行每一个handler(function),handler业务完成后,通过调用next(),决定是否调用下一个handler,也就是所谓的链式处理。
三 路由
1.可以把路由定义为两部分,第一部分是HTTP请求方法,通常是get或post。第二部分是URL中指定的路径。
app.get(path,[middleware],callback)
app.post(path,[middleware],callback)
其中,middleware是回调函数执行前要应用的中间件函数,callback是应该处理该请求并把响应发回给客户端的请求处理程序,callback以Request对象作为第一个参数,以Response对象作为第二个参数。
此外,Express还提供了app.all()方法,该方法与post、get一样,唯一的区别是,app.all()用于指定路径的每个请求,不管是任何一种方法。同时app.all()还可以接受*作为路径的通配符,这对于实现记录请求日志和其他特殊的功能来处理请求是一个很棒的特性,如:
app.all('*',function(req,res){ //全部路径的全局处理程序 });
2.在路由中应用参数
在复杂系统中,路由数量会很多,为了减少路由数量,可以在URL中实现参数。通过路由,可以为不同的请求提供唯一值来定义应用程序如何处理请求并生成响应。
实现路由参数主要有4种方法:
(1)查询字符串,如?key=value&key=value...
var express=require('express'); var url=require('url'); var app=express(); app.get('/find',function(req,res){ var url_parts=url.parse(req.url,true); var query=url_parts.query; res.send('Finding Book:Author: '+query.author+' Title: '+query.title); });
如果是下面的URL:/find?author=Brad&title=Node
那么res.send()方法返回的就是:Finding Book:Author:Brad Title: Node
(2)正则表达式
app.get(/^/book/(w+):(w+)?$/,function(req,res){ res.send('Get Book: Chapter: '+req.params[0]+' page: '+req.params[1]); });
如果是下面的URL:/book/12:15
res.send()方法返回:
Get Book: Chapter: 12 page: 15
注意:这里的参数的值未被命名,req.params是与URL路径中的条目匹配的数组。
(3)使用已定义的参数来应用路由参数
app.get('/user/:userid',function(req,res){ res.send('Get User: '+req.param('userid')); });
如果是下面的URL:/user/111
res.send()方法返回: Get User: 111
(4)为已定义的参数应用回调函数
app.param(param,function(req,res,next,value){})
注意,这里的next是一个用于已注册的下一个app.param()回调的回调函数,必须要在回调函数中的某处调用next(),否则回调链会被破坏。value是从URL路径解析的参数的值。
3.Request对象
Request对象是作为第一个参数传递到路由处理程序,它的一些常用属性和方法:
originalUrl 请求的原始URL字符串
protocol 协议的字符串,如http或https
ip 请求的ip地址
path 请求的路径部分
host 请求的主机名
method HTTP方法
query 请求的URL的查询字符串部分
fresh 一个布尔值,当最后修改与当前匹配时为true
stale 一个布尔值,当最后修改与当前匹配时为false
secure 一个布尔值,当建立TLS连接时为true
acceptsCharset(charset) 一个方法,如果由charset指定的字符集受支持,返回true
get(header) 返回header的值的方法
headers 请求标头的对象形式
4.Response对象
传递到路由处理程序的Response对象提供了必要的功能来建立和发送适当的HTTP响应。
(1)设置标头
get(header) 返回指定的header参数的值
set(header,value) 设置header参数的值
set(headerObj) 接受一个对象,包括多个'header':'value'属性
locatio(path) 把location标头设置为指定的path参数
type(type_string) 根据type_string参数设置Content-Type标头
attachment([filepath]) 把Content-Disposition标头设置为attachment,并且如果指定filepath,则Content-Type头是基于文件扩展名设置的
(2)设置状态
res.status(200); //正确
300 Rediction重定向
400 Bad Request错误的请求
401 Unauthorized未经许可
403 Forbidden禁止
500 Server Error服务器错误
(3)发送响应
res.send(status,[body])
body是一个String或者Buffer对象,如果指定Buffer对象,内容类型就被自动设置为application/octet-stream(应用程序/八位字节流)
(4)发送JSON响应
res.json(status,[object])
如:
app.get('/json',function(req,res){ app.set('json spaces',4); res.json({name:'bob',built:'1223',centers:['art','maths']}); }); app.get('jsonp',function(res,req){ app.set('jsonp callback name','cb'); res.jsonp({name:'bob',built:'1223',centers:['art','maths']}); });
注意,jsonp callback name被设置为cb,意味着客户端需要在URL中传递的不是?callback=<function>,而是?cb=<function>
(5)发送文件
res.sendFile(path,[options],[callback])
其中,path指向你要发送给客户端的文件,options参数是一个对象,包含了一个maxAge属性定义的最长期限和root属性(用来支持path参数相对路径的根路径)。当文件传输完成时,回调函数被调用,并接受一个错误作为唯一的参数。
如:
app.get('/image',function(req,res){ res.sendFile('arch.jpg',{maxAge:1, //24*60*60*1000 root:'./views'}, function(err){ if(err){ console.log('Error'); }else{ console.log('Success'); } }); });
(6)发送下载响应:
res.download(path,[filename],[callback])
(7)重定向响应:
res.redirect(path);
如:
app.get('/google',function(req,res){ res.redirect('http://google.com'); });
看路由的一些例子
(1)简单的get请求
app.js
var express = require('express'); var app = express(); var index = require('./routes/index'); var users = require('./routes/users'); app.use('/', index); app.use('/users', users);
index.js
var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/', function(req, res, next) { res.send('hello,index'); }); module.exports = router;
user.js
var express = require('express'); var router = express.Router(); /* GET users listing. */ router.get('/', function(req, res, next) { res.send('respond with a resource'); }); module.exports = router;
项目结构如图:
运行结果:
(2)看一个正则匹配的例子
在index.js添加:
router.get('/ab*cd',function(req,res){ console.log('/ab*cd GET请求'); res.send('正则匹配'); });
(3)通过表单提交的post请求
新建index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form method="post" action="http://localhost:3000/"> <input type="submit" value="访问" /> </form> </body> </html>
点击访问后出现:
三 实现模板引擎
1.一个日益增长的趋势是,使用模板文件和应用程序数据,借助模板引擎来生成HTML,而不是从头开始构建HTML文件。Express中两个重要的模板,Jade和内嵌的javascript(EJS)。
Jade使用HTML的速记符号模板,模板文件非常小,但是需要掌握另一种语言;EJS使用特殊的符号在正常的HTML文档中嵌入javascript,使得它更容易从正常的HTML过度,但是该HTML会比原始文档复杂的多,不如Jade模板简洁。
2.安装jade和ejs:
npm install jade --save
npm install ejs --save
安装后可以到package.json中查看
3.定义引擎模板
var app=express(); app.set('views','./views'); //也可以写成app.set('views',path.join(_dirname,'views'));即根目录下的views文件夹下 app.set('view engine','jade');
看一个例子:
app.js:
var express = require('express'); var app = express(); var path = require('path'); //指明模板目录:./views app.set('views', path.join(__dirname, 'views')); //使用ejs引擎 app.set('view engine', 'ejs');
node中的path.join方法:将多个参数组合成一个path
path.join([path1],[path2],...);
注意:该方法属于path模块,使用前需要引入path模块
index.js
var express = require('express'); var router = express.Router(); //寻找views/index,提交ejs渲染,并返回结果 router.get('/', function(req, res, next) { res.render('index',{title:'express'}); }); module.exports = router;
使用ejs模板,index.ejs
<!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <h1><%= title %></h1> <p>Welcome to <%= title %></p> </body> </html>
4.引入静态文件
在app.js中添加:
app.use(express.static(path.join(__dirname, 'public')));
查看一下目录文件,这里我们要引用的是public/stylesheets/style.css
index.ejs
<!DOCTYPE html> <html> <head> <title><%= title %></title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <h1><%= title %></h1> <p>Welcome to <%= title %></p> </body> </html>
style.css:
body { padding: 50px; font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; color: #00B7FF; }
四 Express中间件
1.Express提供的大部分功能是通过中间件函数完成的,这些中间件函数在nodejs收到请求的时点和发送响应的时点之间执行。Express的connect模块提供了中间件框架,让你方便的在全局或路径级别或为单个路由插入中间件功能。通过Express支持的中间件可以让你快速提供静态文件,实现cookie,支持会话,处理post数据等等,你甚至可以创建自己的自定义中间件函数,并利用它们来预处理请求和提供自己的功能。
2.有哪些中间件
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压缩支持
caurf 提供跨站点请求伪造保护
3.安装:
npm install body-parser --save
也可以把express添加到package.json模块,以确保当你部署应用程序时,这些模块被安装。
4.分配中间件
(1)在全局范围内把中间件分配给某个路径
要对所有路由指定中间件,可以在Express app对象上实现Use()方法:
use([path],middleware)
其中,path是可选的,默认为/,意味着所有的路径,middleware是一个函数,即function(req,res,next){},每个中间件函数都有一个构造函数,它返回相应的中间件功能。next是要执行的下一个中间件函数。
例如,把body-parser中间件应用于所有路径:
var express=require('express'); var bodyParser=require('body-parser'); var app=express(); app.use('/',bodyParser());
(2)把中间件分配到单个路由
var express=require('express'); var bodyParser=require('body-parser'); var app=express(); app.get('/parseRoute',bodyParser(),function(req,res){ //function });
(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());
注意,你分配函数的顺序就是它们在请求中被应用的顺序。一些中间件需要被添加在别的中间件函数前面。