ThinkJS 路由

2021-09-17 10:22 更新

路由

當(dāng)用戶訪問一個 URL 時,最終執(zhí)行哪個模塊下哪個控制器的哪個操作,這是由路由來解析后決定的。

ThinkJS 提供了一套靈活的路由機(jī)制,除了默認(rèn)的解析外,還可以支持多種形式的自定義路由,讓 URL 更加簡單友好。

URL 解析為 pathname

當(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

pathname 過濾

有時候?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é)果為:

  • module 為 admin
  • controller 為 group
  • action 為 detail,對應(yīng)的方法名為 detailAction

如果項(xiàng)目里并沒有 admin 這個模塊或者這個模塊被禁用了,那么識別后的結(jié)果為:

  • module 為默認(rèn)模塊 home
  • controller 為 admin
  • action 為 group,對應(yīng)的方法名為 groupAction
  • 參數(shù)為 {detail: ''}

大小寫轉(zhuǎn)化

路由識別后,modulecontroller 和 Action 值都會自動轉(zhuǎn)為小寫。如果 Action 值里有 _,會作一些轉(zhuǎn)化,如:假設(shè)識別后的 Controller 值為 index,Action 值為 user_add,那么對應(yīng)的 Action 方法名為userAddAction,但模版名還是 index_user_add.html。

路由默認(rèn)值

當(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ī)則

開啟自定義路由后,就可以通過路由規(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ī)則路由

規(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)路由

靜態(tài)路由是一種純字符串的完全匹配方式,寫法和識別都很簡單,功能也相對要弱很多。

export default [
  ["list", "home/article/list"]
]

假如訪問的 URL 為 http://www.example.com/list,那么替換后的 pathname 為 home/article/list。

優(yōu)化路由性能

上面已經(jīng)說到,自定義路由是個數(shù)組,數(shù)組每一項(xiàng)是個具體的路由規(guī)則,匹配時是從前向后逐一進(jìn)行匹配。如果這個路由表比較大的話,可能會有性能問題。

為了避免有性能問題,ThinkJS 提供了一種更加高效的自定義路由方式,按模塊來配置路由。使用這種方式,路由配置格式跟上面稍微有所不同。

common/config/route.js

使用這種方式后,通用模塊里的路由配置不再配置具體的路由規(guī)則,而是配置哪些規(guī)則命中到哪個模塊。如:

export default {
  admin: { 
    reg: /^admin/ //命中 admin 模塊的正則
  },
  home: { //默認(rèn)走 home 模塊

  }
}

admin/config/route.js

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ù)量,提供匹配效率。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號