新聞中心
?GOframe?框架自建了非常強大的路由功能,提供了比任何同類框架更加出色的路由特性,支持流行的命名匹配規(guī)則、模糊匹配規(guī)則及字段匹配規(guī)則,并提供了優(yōu)秀的優(yōu)先級管理機制。

公司主營業(yè)務(wù):網(wǎng)站設(shè)計、網(wǎng)站建設(shè)、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團隊。公司秉承以“開放、自由、嚴(yán)謹、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團隊有機會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)推出三河免費做網(wǎng)站回饋大家。
一個示例
在真正開啟本章的核心內(nèi)容之前,我們先來看一個簡單的動態(tài)路由使用示例:
package main
import (
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/frame/g"
)
func main() {
s := g.Server()
s.BindHandler("/:name", func(r *ghttp.Request){
r.Response.Writeln(r.Router.Uri)
})
s.BindHandler("/:name/update", func(r *ghttp.Request){
r.Response.Writeln(r.Router.Uri)
})
s.BindHandler("/:name/:action", func(r *ghttp.Request){
r.Response.Writeln(r.Router.Uri)
})
s.BindHandler("/:name/*any", func(r *ghttp.Request){
r.Response.Writeln(r.Router.Uri)
})
s.BindHandler("/user/list/{field}.html", func(r *ghttp.Request){
r.Response.Writeln(r.Router.Uri)
})
s.SetPort(8199)
s.Run()
}以上示例中展示了?GoFrame?框架支持的三種模糊匹配路由規(guī)則,?:name?、?*any?、?{field}?分別表示命名匹配規(guī)則、模糊匹配規(guī)則及字段匹配規(guī)則。不同的規(guī)則中使用?/?符號來劃分層級,路由檢索采用深度優(yōu)先算法,層級越深的規(guī)則優(yōu)先級也會越高。我們運行以上示例,通過訪問幾個URL來看看效果:
URL 結(jié)果
http://127.0.0.1:8199/user/list/2.html /user/list/{field}.html
http://127.0.0.1:8199/user/update /:name/update
http://127.0.0.1:8199/user/info /:name/:action
http://127.0.0.1:8199/user /:name/*any在這個示例中我們也可以看到,由于優(yōu)先級的限制,路由規(guī)則?/:name?會被?/:name/*any?規(guī)則覆蓋,將會無法被匹配到,所以在分配路由規(guī)則的時候,需要進行統(tǒng)一規(guī)劃和管理,避免類似情況的產(chǎn)生。
注冊規(guī)則
路由注冊參數(shù)
我們來看一下之前一直使用的?BindHandler?的原型:
func (s *Server) BindHandler(pattern string, handler interface{})該方法是路由注冊的最基礎(chǔ)方法,其中的?pattern?為路由注冊規(guī)則字符串,在其他路由注冊方法中也會使用到,參數(shù)格式如下:
[HTTPMethod:]路由規(guī)則[@域名]其中?HTTPMethod?(支持的Method:?GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE?)和?@域名?為非必需參數(shù),一般來說直接給定路由規(guī)則參數(shù)即可,?BindHandler?會自動綁定所有的請求方式,如果給定?HTTPMethod?,那么路由規(guī)則僅會在該請求方式下有效。?@域名?可以指定生效的域名名稱,那么該路由規(guī)則僅會在該域名下生效。
?BindHandler?是最原生的路由注冊方法,在大部分場景中,我們通常使用分組路由方式來管理理由。
我們來看一個例子:
package main
import (
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/frame/g"
)
func main() {
s := g.Server()
// 該路由規(guī)則僅會在GET請求下有效
s.BindHandler("GET:/{table}/list/{page}.html", func(r *ghttp.Request){
r.Response.WriteJson(r.Router)
})
// 該路由規(guī)則僅會在GET請求及l(fā)ocalhost域名下有效
s.BindHandler("GET:/order/info/{order_id}@localhost", func(r *ghttp.Request){
r.Response.WriteJson(r.Router)
})
// 該路由規(guī)則僅會在DELETE請求下有效
s.BindHandler("DELETE:/comment/{id}", func(r *ghttp.Request){
r.Response.WriteJson(r.Router)
})
s.SetPort(8199)
s.Run()
}其中返回的參數(shù)?r.Router?是當(dāng)前匹配的路由規(guī)則信息,訪問當(dāng)該方法的時候,服務(wù)端會輸出當(dāng)前匹配的路由規(guī)則信息。執(zhí)行后,我們在終端使用?curl?命令進行測試:
$ curl -XGET http://127.0.0.1:8199/order/list/1.html
{"Domain":"default","Method":"GET","Priority":3,"Uri":"/{table}/list/{page}.html"}
$ curl -XGET http://127.0.0.1:8199/order/info/1
Not Found
$ curl -XGET http://localhost:8199/order/info/1
{"Domain":"localhost","Method":"GET","Priority":3,"Uri":"/order/info/{order_id}"}
$ curl -XDELETE http://127.0.0.1:8199/comment/1000
{"Domain":"default","Method":"DELETE","Priority":2,"Uri":"/comment/{id}"}
$ curl -XGET http://127.0.0.1:8199/comment/1000
Not Found值得說明的是,在大多數(shù)場景下,我們很少直接在路由規(guī)則中使用?@域名?這樣的規(guī)則來限定路由注冊的域名,而是使用?ghttp.Server.Domain(domains string)?方法來獲得指定域名列表的管理對象,隨后使用該域名對象進行路由注冊,域名對象即可實現(xiàn)對指定域名的綁定操作。
精準(zhǔn)匹配規(guī)則
精準(zhǔn)匹配規(guī)則即未使用任何動態(tài)規(guī)則的規(guī)則,如:?user?、?order?、?info?等等這種確定名稱的規(guī)則。在大多數(shù)場景下,精準(zhǔn)匹配規(guī)則會和動態(tài)規(guī)則一起使用來進行路由注冊(例如:?/:name/list?,其中層級1?:name?為命名匹配規(guī)則,層級2?list?是精準(zhǔn)匹配規(guī)則)。
動態(tài)路由規(guī)則
動態(tài)路由規(guī)則分為三種:命名匹配規(guī)則、模糊匹配規(guī)則和字段匹配規(guī)則。動態(tài)路由的底層數(shù)據(jù)結(jié)構(gòu)是由層級哈希表和雙向鏈表構(gòu)建的路由樹,層級哈希表便于高效率地層級匹配?URI?;數(shù)據(jù)鏈表用于優(yōu)先級控制,同一層級的路由規(guī)則按照優(yōu)先級進行排序,優(yōu)先級高的規(guī)則排在鏈表頭。底層的路由規(guī)則與請求?URI?的匹配計算采用的是正則表達式,并充分使用了緩存機制,執(zhí)行效率十分高效。
所有匹配到的參數(shù)都將會以?Router?參數(shù)的形式傳遞給業(yè)務(wù)層,可以通過?ghttp.Request?對象的以下方法獲?。?/p>
func (r *Request) GetRouterValue(key string, def ...interface{}) interface{}
func (r *Request) GetRouterVar(key string, def ...interface{}) *gvar.Var
func (r *Request) GetRouterString(key string, def ...interface{}) string也可以使用?ghttp.Request.Get*?方式進行獲取。
命名匹配規(guī)則
使用?:name?方式進行匹配(?name?為自定義的匹配名稱),對?URI?指定層級的參數(shù)進行命名匹配(類似正則([^/]+),該URI層級必須有值),對應(yīng)匹配參數(shù)會被解析為Router參數(shù)并傳遞給注冊的服務(wù)接口使用。
匹配示例1:
rule: /user/:user
/user/john match
/user/you match
/user/john/profile no match
/user/ no match匹配示例2:
rule: /:name/action
/john/name no match
/john/action match
/smith/info no match
/smith/info/age no match
/smith/action match匹配示例3:
rule: /:name/:action
/john/name match
/john/info match
/smith/info match
/smith/info/age no match
/smith/action/del no match
模糊匹配規(guī)則
使用?*any?方式進行匹配(?any?為自定義的匹配名稱),對?URI?指定位置之后的參數(shù)進行模糊匹配(類似正則?(.*)?,該?URI?層級可以為空),并將匹配參數(shù)解析為?Router?參數(shù)并傳遞給注冊的服務(wù)接口使用。
匹配示例1:
rule: /src/*path
/src/ match
/src/somefile.go match
/src/subdir/somefile.go match
/user/ no match
/user/john no match匹配示例2:
rule: /src/*path/:action
/src/ no match
/src/somefile.go match
/src/somefile.go/del match
/src/subdir/file.go/del match匹配示例3:
rule: /src/*path/show
/src/ no match
/src/somefile.go no match
/src/somefile.go/del no match
/src/somefile.go/show match
/src/subdir/file.go/show match
/src/show match
字段匹配規(guī)則
使用?{field}?方式進行匹配(?field?為自定義的匹配名稱),可對?URI?任意位置的參數(shù)進行截取匹配(類似正則?([\w\.\-]+)?,該?URI?層級必須有值,并且可以在同一層級進行多個字段匹配),并將匹配參數(shù)解析為?Router?參數(shù)并傳遞給注冊的服務(wù)接口使用。
匹配示例1:
rule: /order/list/{page}.php
/order/list/1.php match
/order/list/666.php match
/order/list/2.php5 no match
/order/list/1 no match
/order/list no match匹配示例2:
rule: /db-{table}/{id}
/db-user/1 match
/db-user/2 match
/db/user/1 no match
/db-order/100 match
/database-order/100 no match匹配示例3:
rule: /{obj}-{act}/*param
/user-delete/10 match
/order-update/20 match
/log-list match
/log/list/1 no match
/comment/delete/10 no match
動態(tài)路由示例
package main
import (
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/frame/g"
)
func main() {
s := g.Server()
// 一個簡單的分頁路由示例
s.BindHandler("/user/list/{page}.html", func(r *ghttp.Request){
r.Response.Writeln(r.Get("page"))
})
// {xxx} 規(guī)則與 :xxx 規(guī)則混合使用
s.BindHandler("/{object}/:attr/{act}.php", func(r *ghttp.Request){
r.Response.Writeln(r.Get("object"))
r.Response.Writeln(r.Get("attr"))
r.Response.Writeln(r.Get("act"))
})
// 多種模糊匹配規(guī)則混合使用
s.BindHandler("/{class}-{course}/:name/*act", func(r *ghttp.Request){
r.Response.Writeln(r.Get("class"))
r.Response.Writeln(r.Get("course"))
r.Response.Writeln(r.Get("name"))
r.Response.Writeln(r.Get("act"))
})
s.SetPort(8199)
s.Run()
}執(zhí)行后,我們可以通過?curl?命令或者瀏覽器訪問的方式進行測試,以下為測試結(jié)果:
$ curl -XGET http://127.0.0.1:8199/user/list/1.html
1
$ curl -XGET http://127.0.0.1:8199/user/info/save.php
user
info
save
$ curl -XGET http://127.0.0.1:8199/class3-math/john/score
class3
math
john
score
優(yōu)先級控制
優(yōu)先級控制按照深度優(yōu)先策略,主要的幾點因素:
- 層級越深的規(guī)則優(yōu)先級越高;
- 同一層級下,精準(zhǔn)匹配優(yōu)先級高于模糊匹配;
- 同一層級下,模糊匹配優(yōu)先級:字段匹配 > 命名匹配 > 模糊匹配;
我們來看示例(左邊的規(guī)則優(yōu)先級比右邊高):
/:name > /*any
/user/name > /user/:action
/:name/info > /:name/:action
/:name/:action > /:name/*action
/:name/{action} > /:name/:action
/src/path/del > /src/path
/src/path/del > /src/path/:action
/src/path/*any > /src/path 名稱欄目:創(chuàng)新互聯(lián)GoFrame教程:GoFrame路由管理-路由規(guī)則
標(biāo)題路徑:http://fisionsoft.com.cn/article/ccdogie.html


咨詢
建站咨詢
