定义:路由是用来把请求映射到路由处理程序。应用程序一启动就配置了路由,并且可以从URL中提取值用于处理请求。它还负责使用 ASP.NET 应用程序中定义的路由来生成链接。
路由使用 routes 类 ( iRouter 的实现) 做到:
- 映射传入的请求到 路由处理程序
- 生成响应中使用的 URLs
1. 服务器端路由
对于服务器来说,当接收到客户端发来的HTTP请求,会根据请求的URL,来找到相应的映射函数,然后执行该函数,并将函数的返回值发送给客户端。对于最简单的静态资源服务器,可以认为,所有URL的映射函数就是一个文件读取操作。对于动态资源,映射函数可能是一个数据库读取操作,也可能是进行一些数据的处理,等等。
以Express为例,
app.get('/', (req, res) => {
res.sendFile('index')
})
app.get('/users', (req, res) => {
db.queryAllUsers()
.then(data => res.send(data))
})
这里定义了两条路由:
- 当访问/的时候,会返回index页面
- 当访问/users的时候,会从数据库中取出所有用户数据并返回
不仅仅是URL
在router匹配route的过程中,不仅会根据URL来匹配,还会根据请求的方法来看是否匹配。例如上面的例子,如果通过POST方法来访问/users,就会找不到正确的路由。
2. 客户端路由
对于客户端(通常为浏览器)来说,路由的映射函数通常是进行一些DOM的显示和隐藏操作。这样,当访问不同的路径的时候,会显示不同的页面组件。客户端路由最常见的有以下两种实现方案:
- 基于Hash
- 基于History API
(1) 基于Hash
我们知道,URL中#及其后面的部分为hash。例如:
const url = require('url')
var a = url.parse('http://example.com/a/b/#/foo/bar')
console.log(a.hash)
// => #/foo/bar
hash仅仅是客户端的一个状态,也就是说,当向服务器发请求的时候,hash部分并不会发过去。
通过监听window对象的hashChange事件,可以实现简单的路由。例如:
window.onhashchange = function() {
var hash = window.location.hash
var path = hash.substring(1)
switch (path) {
case '/':
showHome()
break
case '/users':
showUsersList()
break
default:
show404NotFound()
}
}
(2) 基于History API
通过HTML5 History API可以在不刷新页面的情况下,直接改变当前URL。详细用法可以参考:
Manipulating the browser history
Using the HTML5 History API
我们可以通过监听window对象的popstate事件,来实现简单的路由:
window.onpopstate = function() {
var path = window.location.pathname
switch (path) {
case '/':
showHome()
break
case '/users':
showUsersList()
break
default:
show404NotFound()
}
}
但是这种方法只能捕获前进或后退事件,无法捕获pushState和replaceState,一种最简单的解决方法是替换pushState方法,例如:
var pushState = history.pushState
history.pushState = function() {
pushState.apply(history, arguments)
// emit a event or just run a callback
emitEventOrRunCallback()
}
不过,最好的方法还是使用实现好的history库。
(3) 两种实现的比较
总的来说,基于Hash的路由,兼容性更好;基于History API的路由,更加直观和正式。
但是,有一点很大的区别是,基于Hash的路由不需要对服务器做改动,基于History API的路由需要对服务器做一些改造。下面来详细分析。
假设服务器只有如下文件(script.js被index.html所引用):
/-
|- index.html
|- script.js
基于Hash的路径有:
http://example.com/
http://example.com/#/foobar
基于History API的路径有:
http://example.com/
http://example.com/foobar
当直接访问http://example.com/
的时候,两者的行为是一致的,都是返回了index.html
文件。
当从http://example.com/
跳转到http://example.com/#/foobar
或者http://example.com/foobar
的时候,也都是正常的,因为此时已经加载了页面以及脚本文件,所以路由跳转正常。
当直接访问http://example.com/#/foobar
的时候,实际上向服务器发起的请求是http://example.com/
,因此会首先加载页面及脚本文件,接下来脚本执行路由跳转,一切正常。
当直接访问http://example.com/foobar
的时候,实际上向服务器发起的请求也是http://example.com/foobar
,然而服务器端只能匹配/
而无法匹配/foobar
,因此会出现404错误。
因此如果使用了基于History API的路由,需要改造服务器端,使得访问/foobar
的时候也能返回index.html
文件,这样当浏览器加载了页面及脚本之后,就能进行路由跳转了。