Express 4.8.x—路由详解
路由详解
路由处理器执行顺序
编码的顺序决定了路由处理器执行顺序。
app.get(“/test”,function(req,res,next){ console.log(“router A”); next(); }) app.get(“/test”,function(req,res,next){ console.log(“router B”); next(); })
这个顺序编码,浏览器访问/test 时,终端会打印出:
router A router B
无论调用 app.use 、app.all、app.get、app.post 都是一样的,按编码顺序执行。还需强调一点,这个顺序执行的前提是,一致的路由;这个路由的一致,体现在相同的方法和相同的路径。
app.get(“/test”,function(req,res,next){ console.log(“router A”); next(); }) app.post(“/test”,function(req,res,next){ console.log(“router B”); next(); })
这样就没有顺序可言,因为顺序的前提必须要是一致的路由。next
这个方法调用之前,不会调用之后的路由处理器。
app.get(“/test”,function(req,res,next){ console.log(“router A”); }) app.get(“/test”,function(req,res,next){ console.log(“router B”); next(); })
这个只会打印出 router A ,因为第一个路由处理器没有调用next() 方法。
始终我们在浏览器都没看到响应,是因为从来没调用过响应方法,比如 res.send 或 res.render 方法。
app.get(“/test”,function(req,res,next){ console.log(“router A”); next() }) app.get(“/test”,function(req,res,next){ console.log(“router B”); res.send(“router B”); })
这样浏览器会显示出 router B 字符串,我们发现第二个路由处理器没有调用next ,因为调用next() 的目的是执行之后的路由处理器,如果后面没有就无需调用。另外要注意一点,调用了任何响应方法,都表示响应的任务完成。比如下面代码:
app.get(“/test”,function(req,res,next){ console.log(“router A”); res.send(“router A”) next(); }) app.get(“/test”,function(req,res,next){ console.log(“router B”); res.send(“router B”); next(); }) app.get(“/test”,function(req,res,next){ console.log(“router C”); res.send(“router C”); next(); })
调用后浏览器只会显示出router A,因为 “ 调用了任何响应方法,都表示响应的任务完成。 ” ,当然第二个路由响应器还是会执行,只不过所有的响应方法都不再起作用。
而其他代码还会起作用,终端会打印出:
router A router B router C
app.all
app.all
表示响应所有http方法。
app.all(“/test”,function(req,res,next){ console.log(“app.all method”); next(); }) app.get("/test",function(req,res,next){ res.send("app.get method") }) app.post("/test",function(req,res,next){ res.send("app.post method") })
无论我们通过 get 或 post http方法访问,终端都会打印app.all method。 用 app.use 代替 app.all 效果也一样,但use不支持多路由处理器,比如下面代码:
app.all("/test",function(req,res,next){ console.log("app.all method"); next(); },function(req,res,next){ console.log("app 2"); next(); }) app.get("/test",function(req,res,next){ res.send("app.get method") }) app.post("/test",function(req,res,next){ res.send("app.post method") })
终端会打印出
app.all method app 2
但用use代替all方法,只打印出
app.all method
app.all / app.get / app.post
方法支持多路由处理器链 ,app.use
方法不支持,但它支持express.Router的实例,下面就来探讨 express.Router 类。
express.Router
一个express.Router 对象,可以理解为是一个独立的 mini app,它也可以调用use方法加入中间件,但只作用于自身。
通过 var router = express.Router([可选参数])
创建一个路由器对象。
可选参数对象有两个可选值,caseSensitive 区分大小写,例如/Foo 和 /foo ,默认false关闭。strict 严格路由,例如 /foo 和 /foo/ ,默认false关闭。
它是个mini app,所以它的行为方式和app一致,下面是个例子:
var router = express.Router(); router.get("/abc",function(req,res,next){ res.send("abc abc"); }) app.use("/user",router);
通过 /user/abc 可以访问,通过app.use方法加入到应用程序的路由链上。
比如我们系统中有一些子系统,user 、book和 forum:
app.use("/user",require(“./user”)); app.use("/book",require(“./user”)); app.use("/forum",require(“./user”));
模块化很方便,便于管理和维护。既然它是mini app,它自身的use方法也可以应用其他router。例如:
var sub = express.Router(); sub.get("/sub",function(req,res,next){ res.send("sub is me"); }) var router = express.Router(); router.use("/abc",sub); app.use("/user",router);
通过 /user/abc/sub 可以访问到,实际开发不会这么写,这里只是举个例子。
另外, 无论app还是mini app的Router对象,都支持下面的糖衣写法:
// 也可以用于 app.route router.route('/users/:user_id') .all(function(req, res, next) { }) .get(function(req, res, next) { },function(req,res,next){}) .put(function(req, res, next) { }) .post(function(req, res, next) { }) .delete(function(req, res, next) { })
泛式路由
/user/id0001
这是明确路由,泛式路由在“web框架开发实战”部分已经介绍过了,这里不做说明。
/user/:id
和 /user/*
都属于泛式路由,在express如何获得路由参数的呢?这个放在下一节Request请求
来讲。
这个部分我们要探讨express泛式路由的写法。
/user/:id
这个路由通过,user/id
都可访问到。/user/:id?
这个路由通过,/user
和user/id
都可访问到。/user/*
这个路由通过,/user
和user/id
都可访问到。/user/*/id?
这个路由通过,/user
和user/id001
和user/xxx/id001
都可访问到。/user/*/:id
这个路由通过,user/id001
和user/xxx/id001
都可访问到。
这两个写法的差异在于,定义了:id 就可通过 req.params.id 得到改参数。
通过正则可以写复杂些的路由器。例如:
router.get(/^\/commits\/(\w+)(?:\.\.(\w+))?$/, function(req, res){ var from = req.params[0]; var to = req.params[1] || 'HEAD'; res.send('commit range ' + from + '..' + to); });
通过 /commits/71dbb9c..4c084f9
可以访问到,params[0] 对应的是 71dbb9c , params[1] 对应的是 4c084f9