NodeJS框架express的路径映射(路由)功能及控制
javascript
咱们知道Express是一个基于NodeJS的很是优秀的服务端开发框架,本篇CSSer将提供express框架的route和route control章节,route实现了客户端请求的URL的路径映射功能,暂且译为路由或URL映射吧。若是你仍是不太理解,相信看完本篇文章将会有些收获的。css
Express利用HTTP动做提供了有意义并富有表现力的URL映射API,例如咱们可能想让用户账号的URL看起来像“/user/12”的样子,下面的例子就能实现这样的路由,其中与占位标识符(本例为:id)相关的值能够被req.params获取到。java
app.get('/user/:id', function(req, res){ res.send('user ' + req.params.id); });
上例中当咱们访问/user/12时返回“user 12”,CSSer注:app.get至关于在服务器注册了一个监听get请求事件的侦听器,当请求的URL知足第一个参数时,执行后面的回调函数,该过程是异步的。jquery
路由是一个能够被内部编译成正则表达式的简单字符串,好比当/user/:id被编译后,被内部编译后的正则表达式字符串看起来会是下面的样子(简化后):正则表达式
\/user\/([^\/]+)\/?
要实现复杂点的,咱们能够传入正则表达式直接量,由于正则捕获组是匿名的所以咱们能够经过req.params进行访问,第一个捕获组应该是req.params[0],第二个应该是req.params[1],以此类推。数据库
app.get(/^\/users?(?:\/(\d+)(?:\.\.(\d+))?)?/, function(req, res){ res.send(req.params); });
经过Linux的curl命令来测试咱们定义的路由:express
$ curl http://cssercom:3000/user [null,null] $ curl http://cssercom:3000/users [null,null] $ curl http://cssercom:3000/users/1 ["1",null] $ curl http://cssercom:3000/users/1..15 ["1","15"]
下面是一些路由例子,以及与之相匹配的关联路径:apache
"/user/:id" /user/12 "/users/:id?" /users/5 /users "/files/*" /files/jquery.js /files/javascripts/jquery.js "/file/*.*" /files/jquery.js /files/javascripts/jquery.js "/user/:id/:operation?" /user/1 /user/1/edit "/products.:format" /products.json /products.xml "/products.:format?" /products.json /products.xml /products "/user/:id.:format?" /user/12 /user/12.json
另外,咱们能够经过POST方式提交json数据,而后利用bodyParser中间件解析json请求体并把json数据返回给客户端:编程
var express = require('express') , app = express.createServer(); app.use(express.bodyParser()); app.post('/', function(req, res){ res.send(req.body); }); app.listen(3000);
一般咱们所使用的占位符(好比/user/:id)都没有任何限制,即用户能够传入各类各样数据类型的id值,若是咱们但愿限制用户id为数字,能够这样写“/user/:id(\d+)”,这样就能保证只有该占位符数据类型为数值类型才会进行路由的相关处理。json
一个应用中能够定义多个路由,咱们能够控制以令其转向下一个路由,Express提供了第三个参数即next()函数。当一个模式不被匹配时,控制将被转回Connect(Express基于Connect模块),同时中间件会继续按照它们在use()中增长的顺序来执行。当多个定义的路由均可能匹配同一个URL时也是如此,除非某个路由并不调用next()且已将响应输出到客户端,不然它们也将按顺序执行。
app.get('/users/:id?', function(req, res, next){ var id = req.params.id; if (id) { // 一回注:若是在这里就将响应内容输出给客户端,那么后续的URL映射将不会被调用 } else { next(); // 将控制转向下一个符合URL的路由 } }); app.get('/users', function(req, res){ // do something else });
app.all()方法能够对全部HTTP动做应用单一调用入口,这在有些状况下颇有用。下面咱们使用该功能来从咱们的模拟数据库中加载一个用户,并把它分配给req.user。
var express = require('express') , app = express.createServer(); var users = [{ name: 'www.csser.com' }]; app.all('/user/:id/:op?', function(req, res, next){ req.user = users[req.params.id]; if (req.user) { next(); } else { next(new Error('cannot find user ' + req.params.id)); } }); app.get('/user/:id', function(req, res){ res.send('viewing ' + req.user.name); }); app.get('/user/:id/edit', function(req, res){ res.send('editing ' + req.user.name); }); app.put('/user/:id', function(req, res){ res.send('updating ' + req.user.name); }); app.get('*', function(req, res){ res.send('what???', 404); }); app.listen(3000);
本节为后补(2011-4-16)。
路由参数预处理经过隐式的数据处理,能够大幅提升应用代码的可读性和请求URL的验证。假如你常常性的从几个路由获取通用数据,如经过/user/:id加载用户信息,一般咱们可能会这样作:
app.get('/user/:userId', function(req, res, next){ User.get(req.params.userId, function(err, user){ if (err) return next(err); res.send('user ' + user.name); }); });
利用预处理后参数能够被映射到回调函数,从而能够提供诸如验证、强制性改变值,甚至从数据库中加载数据等功能。下面咱们将调用app.param()并传入咱们但愿映射到某个中间件的参数,能够看到咱们接收了包含占位符(:userId)值的id参数。在这里能够与日常同样进行用户数据加载以及错误处理,并能简单的经过调用next()将控制权转向下一个预处理或路由(路径控制)。
app.param('userId', function(req, res, next, id){ User.get(id, function(err, user){ if (err) return next(err); if (!user) return next(new Error('failed to find user')); req.user = user; next(); }); });
这样作,不只向上面提到的能够大幅提升路由的可读性,还能在整个应用中共享该部分的逻辑实现,达到复用目的。
app.get('/user/:userId', function(req, res){ res.send('CSSer用户为 ' + req.user.name); });
对于简单的状况如路由占位符验证和强迫改变值,只须要传入1个参数(支持1个参数),期间抛出的异常将自动传入next(err)。
app.param('number', function(n){ return parseInt(n, 10); });
也能够同时将回调函数应用到多个占位符,好比路由/commits/:from-:to来讲,:from和:to都是数值类型,咱们能够将它们定义为数组:
app.param(['from', 'to'], function(n){ return parseInt(n, 10); });
经过本文的学习,咱们应该有些感受了,NodeJS不单单能够实现咱们产品的服务端逻辑,同时咱们还能够利用Javascript作服务器编程,注意是服务器,也就是说,咱们能够利用Javascript来定制以往只能在apache中才能够作到的功能。NodeJS还须要rewrite吗?路径映射更简单更强大,还要rewrite干吗用?