详解NodeJS框架express的路径映射(路由)功能及控制


Posted in NodeJs onMarch 24, 2017

我 们知道Express是一个基于NodeJS的非常优秀的服务端开发框架,本篇CSSer将提供express框架的route和route control章节,route实现了客户端请求的URL的路径映射功能,暂且译为路由或URL映射吧。如果你还是不太理解,相信看完本篇文章将会有些收 获的。

路由(URL映射)

Express利用HTTP动作提供了有意义并富有表现力的URL映射API,例如我们可能想让用户帐号的URL看起来像“/user/12”的样子,下面的例子就能实现这样的路由,其中与占位标识符(本例为:id)相关的值可以被req.params获取到。

app.get('/user/:id', function(req, res){

  res.send('user ' + req.params.id);

});

上例中当我们访问/user/12时返回“user 12”,CSSer注:app.get相当于在服务器注册了一个监听get请求事件的侦听器,当请求的URL满足第一个参数时,执行后面的回调函数,该过程是异步的。

路由是一个可以被内部编译成正则表达式的简单字符串,比如当/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命令来测试我们定义的路由:

$ 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"]

下面是一些路由例子,以及与之相匹配的关联路径:

"/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+)”,这样就能保证只有该占位符数据类型为数值类型才会进行路由的相关处理。

路由控制

一 个应用中可以定义多个路由,我们可以控制以令其转向下一个路由,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);

路由参数预处理

路由参数预处理通过隐式的数据处理,可以大幅提高应用代码的可读性和请求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干嘛用?

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

NodeJs 相关文章推荐
nodejs redis 发布订阅机制封装实现方法及实例代码
Dec 15 NodeJs
搭建简单的nodejs http服务器详解
Mar 09 NodeJs
nodejs开发——express路由与中间件
Mar 24 NodeJs
nodejs实现邮件发送服务实例分享
Mar 29 NodeJs
NodeJs实现定时任务的示例代码
Dec 05 NodeJs
nodejs连接mysql数据库及基本知识点详解
Mar 20 NodeJs
详解webpack打包nodejs项目(前端代码)
Sep 19 NodeJs
NodeJs实现简单的爬虫功能案例分析
Dec 05 NodeJs
NodeJs操作MongoDB教程之分页功能以及常见问题
Apr 09 NodeJs
使用nodeJS中的fs模块对文件及目录进行读写,删除,追加,等操作详解
Feb 06 NodeJs
nodejs使用Sequelize框架操作数据库的实现
Oct 21 NodeJs
Nodejs实现微信分账的示例代码
Jan 19 NodeJs
NodeJS学习笔记之Module的简介
Mar 24 #NodeJs
详解nodejs中的process进程
Mar 19 #NodeJs
nodejs中使用HTTP分块响应和定时器示例代码
Mar 19 #NodeJs
nodejs中向HTTP响应传送进程的输出
Mar 19 #NodeJs
实例分析nodejs模块xml2js解析xml过程中遇到的坑
Mar 18 #NodeJs
nodejs中模块定义实例详解
Mar 18 #NodeJs
Nodejs基于LRU算法实现的缓存处理操作示例
Mar 17 #NodeJs
You might like
php 过滤器实现代码
2010/08/09 PHP
php中时间轴开发(刚刚、5分钟前、昨天10:23等)
2011/10/03 PHP
PHP三元运算符的结合性介绍
2012/01/10 PHP
php中使用addslashes函数报错问题的解决方法
2013/02/06 PHP
PHP之浮点数计算比较以及取整数不准确的解决办法
2015/07/29 PHP
PHP命令行执行整合pathinfo模拟定时任务实例
2016/08/12 PHP
DEDE实现转跳属性文档在模板上调用出转跳地址
2016/11/04 PHP
jQuery操作select的实例代码
2012/06/14 Javascript
JavaScript中的函数重载深入理解
2014/08/04 Javascript
JS/Jquery判断对象为空的方法
2015/06/11 Javascript
js事件冒泡、事件捕获和阻止默认事件详解
2016/08/04 Javascript
Angular2入门教程之模块和组件详解
2017/05/28 Javascript
浅析Javascript中双等号(==)隐性转换机制
2017/10/27 Javascript
nodejs实现范围请求的实现代码
2018/10/12 NodeJs
详解Vue一个案例引发「内容分发slot」的最全总结
2018/12/02 Javascript
详解vue为什么要求组件模板只能有一个根元素
2019/07/22 Javascript
layui table 表格上添加日期控件的两种方法
2019/09/28 Javascript
JS实现长图上下滚动效果
2020/03/19 Javascript
用yum安装MySQLdb模块的步骤方法
2016/12/15 Python
shell命令行,一键创建 python 模板文件脚本方法
2018/03/20 Python
Pytorch中膨胀卷积的用法详解
2020/01/07 Python
Python QT组件库qtwidgets的使用
2020/11/02 Python
让IE可以变相支持CSS3选择器
2010/01/21 HTML / CSS
仿CSDN Blog返回页面顶部功能实现原理及代码
2013/06/30 HTML / CSS
加拿大时尚少女服装品牌:Garage
2016/10/10 全球购物
澳大利亚票务和娱乐市场领导者:Ticketmaster
2017/03/03 全球购物
Carolina Lemke Berlin澳大利亚官网:时尚太阳镜品牌
2019/09/17 全球购物
大学生新闻专业个人自我评价
2013/11/12 职场文书
护理专业自我鉴定
2014/01/30 职场文书
经营理念口号
2014/06/21 职场文书
大学生简历求职信
2014/06/24 职场文书
质监局领导班子对照检查材料思想汇报
2014/09/27 职场文书
小学见习报告
2014/10/31 职场文书
学校工会工作总结2015
2015/05/19 职场文书
python 定义函数 返回值只取其中一个的实现
2021/05/21 Python
pytorch 运行一段时间后出现GPU OOM的问题
2021/06/02 Python