當(dāng)用戶訪問一個 URL 時,最終執(zhí)行哪個模塊下哪個控制器的哪個操作,這是由路由來解析后決定的。
ThinkJS 提供了一套靈活的路由機(jī)制,除了默認(rèn)的解析外,還可以支持多種形式的自定義路由,讓 URL 更加簡單友好。
當(dāng)用戶訪問服務(wù)時,服務(wù)端首先拿到的是一個完整的 URL,如:訪問本頁面,得到的 URL 為http://www.thinkjs.org/zh-CN/doc/2.0/route.html
。
將 URL 進(jìn)行解析得到的 pathname 為 /zh-CN/doc/2.0/route.html
。
有時候?yàn)榱怂阉饕鎯?yōu)化或者一些其他的原因, URL 上會多加一些東西。比如:當(dāng)前頁面是一個動態(tài)頁面,但 URL 最后加了 .html
,這樣對搜索引擎更加友好。但這些在后續(xù)的路由解析中是無用的,需要去除。
ThinkJS 里提供了下面的配置可以去除 pathname
的前綴和后綴內(nèi)容:
export default {
pathname_prefix: "",
pathname_suffix: ".html",
}
上面配置可以在 src/common/config/config.js
中進(jìn)行修改。
pathname 過濾時會自動去除左右的 /
,該邏輯不受上面的配置影響。對 pathname 進(jìn)行過濾后,拿到干凈的 pathname 為 zh-CN/doc/2.0/route
。
注: 如果訪問的 URL 是
http://www.thinkjs.org/
,那么最后拿到干凈的 pathname 則為空字符串。
當(dāng)項(xiàng)目比較復(fù)雜時,可能希望將不同的功能部署在不同的域名下,但代碼還是在一個項(xiàng)目下。如:域名admin.example.com
部署后臺管理的功能,希望映射到 admin
模塊下。
ThinkJS 提供了如下的配置可以進(jìn)行子域名部署,該配置可以在 config/config.js
里設(shè)置:
export default {
subdomain: {
admin: "admin", //表示將 admin.example.com 映射到 admin 模塊下
...
}
}
假如過濾后的 pathname 為 group/detail
,命中了 admin.example.com 這個子域名后,pathname 變?yōu)?code>admin/group/detail。
路由識別默認(rèn)根據(jù) 模塊/控制器/操作/參數(shù)1/參數(shù)1值/參數(shù)2/參數(shù)2值
來識別過濾后的 pathname,如:pathname 為 admin/group/detail
,那么識別后的結(jié)果為:
admin
group
detail
,對應(yīng)的方法名為 detailAction
如果項(xiàng)目里并沒有 admin
這個模塊或者這個模塊被禁用了,那么識別后的結(jié)果為:
home
admin
group
,對應(yīng)的方法名為 groupAction
{detail: ''}
路由識別后,module
、controller
和 Action
值都會自動轉(zhuǎn)為小寫。如果 Action 值里有 _
,會作一些轉(zhuǎn)化,如:假設(shè)識別后的 Controller 值為 index
,Action 值為 user_add
,那么對應(yīng)的 Action 方法名為userAddAction
,但模版名還是 index_user_add.html
。
當(dāng)解析 pathname 沒有對應(yīng)的值時,此時便使用對應(yīng)的默認(rèn)值。其中 module 默認(rèn)值為 home
,controller 默認(rèn)值為 index
,action 默認(rèn)值為 index
。
這些值可以通過下面的配置進(jìn)行修改,配置文件 src/common/config/config.js
:
export default {
default_module: "home",
default_controller: "index",
default_action: "index",
}
默認(rèn)的路由雖然看起來清晰明了,解析起來也很簡單,但看起來不夠簡潔。
有時候需要更加簡潔的路由,這時候就需要使用自定義路由解析了。如:文章的詳細(xì)頁面,默認(rèn)路由可能是:article/detail/id/10
,但我們想要的 URL 是 article/10
這種更簡潔的方式。
開啟自定義路由,需要在 src/common/config/config.js
開啟如下的配置:
export default {
route_on: true
}
開啟自定義路由后,就可以通過路由規(guī)則來定義具體的路由了,路由配置文件為:src/common/config/route.js
,格式如下:
export default [
["規(guī)則1", "需要識別成的pathname"],
["規(guī)則2", {
get: "get請求下需要識別成的pathname",
post: "post請求下需要識別成的pathname"
}]
];
注: 自定義路由每一條規(guī)則都是一個數(shù)組。(至于為什么不用對象,是因?yàn)檎齽t路由下,正則不能作為對象的 key 直接使用)
自定義路由的匹配規(guī)則為:從前向后逐一匹配,如果命中到了該項(xiàng)規(guī)則,則不在向后匹配。
ThinkJS 支持 3 種類型的自定義路由,即:正則路由,規(guī)則路由和靜態(tài)路由。
正則路由是采用正則表示式來定義路由的一種方式,依靠強(qiáng)大的正則表達(dá)式,能夠定義非常靈活的路由規(guī)則。
export default [
[/^article\/(\d+)$/, "home/article/detail?id=:1"]
];
上面的正則會匹配類似 article/10
這樣的 pathname,識別后新的 pathname 為 home/article/detail
,并且將捕獲到的值賦值給參數(shù) id ,這樣在控制器里就可以通過 this.get
方法 來獲取該值。
export default class extends think.controller.base {
detailAction(){
let id = this.get("id");
}
}
如果正則里含有多個子分組,那么可以通過 :1
,:2
,:3
來獲取對應(yīng)的值。
export default [
[/^article\/(\d+)$/, {
get: "home/article/detail?id=:1",
delete: "home/article/delete?id=:1",
post: "home/article/save?id=:1"
}]
];
規(guī)則路由是一種字符串匹配方式,但支持含有一些動態(tài)的值。如:
export default [
["group/:year/:month", "home/group/list"]
]
假如訪問的 URL 為 http://www.example.com/group/2015/10
,那么會命中該項(xiàng)規(guī)則,得到的 pathname 為home/group/list
,同時會添加 2 個參數(shù) year
和 month
,這2個參數(shù)可以在控制器里通過 this.get
方法來獲取。
export default class extends think.controller.base {
listAction(){
let year = this.get("year");
let month = this.get("month");
}
}
靜態(tài)路由是一種純字符串的完全匹配方式,寫法和識別都很簡單,功能也相對要弱很多。
export default [
["list", "home/article/list"]
]
假如訪問的 URL 為 http://www.example.com/list
,那么替換后的 pathname 為 home/article/list
。
上面已經(jīng)說到,自定義路由是個數(shù)組,數(shù)組每一項(xiàng)是個具體的路由規(guī)則,匹配時是從前向后逐一進(jìn)行匹配。如果這個路由表比較大的話,可能會有性能問題。
為了避免有性能問題,ThinkJS 提供了一種更加高效的自定義路由方式,按模塊來配置路由。使用這種方式,路由配置格式跟上面稍微有所不同。
使用這種方式后,通用模塊里的路由配置不再配置具體的路由規(guī)則,而是配置哪些規(guī)則命中到哪個模塊。如:
export default {
admin: {
reg: /^admin/ //命中 admin 模塊的正則
},
home: { //默認(rèn)走 home 模塊
}
}
admin 模塊配置 admin 下的具體路由規(guī)則。
export default [
[/^admin\/(?!api).*$/, "admin/index"],
[/^admin\/api\/(\w+?)(?:\/([\d,]*))?$/, "admin/:1?id=:2&resource=:1"],
];
假設(shè)訪問的 URL 為 http://www.example.com/admin/api
,那么解析后的 pathname 為 admin/api
,匹配common
里的規(guī)則時會命中 admin
模塊,然后再對 admin
模塊下的路由規(guī)則進(jìn)行逐一匹配。通過這種方式后就可以大大減少路由規(guī)則匹配的數(shù)量,提供匹配效率。
更多建議: