欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go標(biāo)準(zhǔn)庫(kù)-ServeMux的使用與模式匹配深入探究

 更新時(shí)間:2024年01月15日 10:53:09   作者:涼涼的知識(shí)庫(kù)  
這篇文章主要為大家介紹了Go標(biāo)準(zhǔn)庫(kù)-ServeMux的使用與模式匹配深入探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

本篇為【深入理解Go標(biāo)準(zhǔn)庫(kù)】系列第二篇

第一篇:http server的啟動(dòng)

第二篇:ServeMux的使用與模式匹配??

根據(jù) Golang 文檔 中的介紹,ServeMux是一個(gè) HTTP 請(qǐng)求多路復(fù)用器(HTTP Request multiplexer)。它按照一定規(guī)則匹配請(qǐng)求URL和已注冊(cè)的模式,并執(zhí)行其中最匹配的模式的Handler

如果你還不知道什么是Handler,強(qiáng)烈建議你先閱讀下:第一篇:http server的啟動(dòng)

基本使用

http.ServeMux實(shí)現(xiàn)了Handler接口

type Handler interface {
 ServeHTTP(ResponseWriter, *Request)
}

http.ServeMux提供兩個(gè)函數(shù)用于注冊(cè)不同Path的處理函數(shù)

  • ServeMux.Handle 接收的是Handler接口實(shí)現(xiàn)

  • ServeMux.HandleFunc 接收的是匿名函數(shù)

type PathBar struct {
}

func (m PathBar) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 w.Write([]byte("Receive path bar"))
 return
}

func main() {
 mx := http.NewServeMux()

 mx.Handle("/bar/", PathBar{})
 mx.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("Receive path foo"))
 })

 http.ListenAndServe(":8009", mx)
}

?? 通過(guò)類(lèi)型轉(zhuǎn)換實(shí)現(xiàn)接口

值得一提的是ServeMux.HandleFunc的實(shí)現(xiàn),底層還是調(diào)用了ServeMux.Handle

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
 if handler == nil {
  panic("http: nil handler")
 }
 mux.Handle(pattern, HandlerFunc(handler))
}

HandlerFunc(handler)這里并不是函數(shù)調(diào)用,而是類(lèi)型轉(zhuǎn)換

type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
 f(w, r)
}

通過(guò)把handler func(ResponseWriter, *Request)轉(zhuǎn)換成類(lèi)型HandlerFunc,而類(lèi)型HandlerFunc實(shí)現(xiàn)了Handler接口

?? 全局默認(rèn)值

當(dāng)沒(méi)有設(shè)置http.Server.Handler屬性時(shí),http.Server就會(huì)使用一個(gè)全局的變量DefaultServeMux *ServeMux來(lái)作為http.Server.Handler的值

下面的代碼和上面的沒(méi)有區(qū)別

func main() {
 http.Handle("/bar/", PathBar{})
 http.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte("Receive path foo"))
 })

 http.ListenAndServe(":8009", nil)
}

Pattern匹配

預(yù)處理

預(yù)處理的是請(qǐng)求的url,以方便匹配,在注冊(cè)時(shí)是不會(huì)做任何處理的

  • 移除host中的端口號(hào)

  • 針對(duì) URL 中包含..或者.的請(qǐng)求,ServeMux 會(huì)對(duì)其 Path 進(jìn)行整理,并匹配到合適的路由模式上

  • 針對(duì) URL 中包含重復(fù)/的請(qǐng)求,ServeMux 會(huì)對(duì)其進(jìn)行重定向

func main() {
 mx := http.NewServeMux()

 mx.HandleFunc("/abc/def", func(writer http.ResponseWriter, request *http.Request) {
  fmt.Fprintln(writer, request.Host, request.URL.Path)
 })

 http.ListenAndServe(":8009", mx)
}

?? 預(yù)處理的是請(qǐng)求的url

pattern是不會(huì)被處理的,而請(qǐng)求的url都是被處理成標(biāo)準(zhǔn)格式

所以如果注冊(cè)如下的pattern,無(wú)論如何也是無(wú)法被命中的

func main() {
 mx := http.NewServeMux()

 mx.HandleFunc("/abc//def", func(writer http.ResponseWriter, request *http.Request) {
  fmt.Fprintln(writer, request.Host, request.URL.Path)
 })
}

無(wú)論是/abc/def還是/abc//def都無(wú)法被命中

$ curl 127.0.0.1:8009/abc/def
404 page not found
$ curl 127.0.0.1:8009/abc//def
<a href="/abc/def" rel="external nofollow"  rel="external nofollow"     >Moved Permanently</a>.

?? 帶 ..或者.請(qǐng)求與重復(fù)/請(qǐng)求的處理不同

包含..或者.整理之后匹配到合適的路由模式上,并不會(huì)重定向

$ curl  127.0.0.1:8009/ccc/../abc/./def
127.0.0.1:8009 /abc/def

含重復(fù)/,會(huì)重定向

$ curl -v  127.0.0.1:8009/abc//def
*   Trying 127.0.0.1:8009...
* Connected to 127.0.0.1 (127.0.0.1) port 8009 (#0)
> GET /abc//def HTTP/1.1
> Host: 127.0.0.1:8009
> User-Agent: curl/7.79.1
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Content-Type: text/html; charset=utf-8
< Location: /abc/def
< Date: Thu, 10 Nov 2022 16:05:13 GMT
< Content-Length: 43
< 
<a href="/abc/def" rel="external nofollow"  rel="external nofollow"     >Moved Permanently</a>.

* Connection #0 to host 127.0.0.1 left intact

路徑匹配

ServeMux 注冊(cè)路由模式的方式有兩種,固定根路徑例如"/favicon.ico",與以根路徑開(kāi)始的子樹(shù),例如"/images/"

?? 固定路徑(fixed, rooted paths)

固定根路徑就是指定一個(gè)固定的 URL 和請(qǐng)求進(jìn)行精確匹配

?? 以根路徑開(kāi)始的子樹(shù)(rooted subtrees)

以根路徑開(kāi)始的子樹(shù)是符合最長(zhǎng)路徑匹配的原則的,例如我們注冊(cè)了兩個(gè)子路徑,/image/gif//image/,URL 為/image/gif/的請(qǐng)求會(huì)優(yōu)先匹配第一個(gè)路由模式,其他路徑會(huì)匹配/image/

?? 注意:

1、凡是/結(jié)尾的路徑都被看作以根路徑開(kāi)始的子樹(shù),因此 / 也被看作以根路徑開(kāi)始的子樹(shù),它不僅匹配/,而且也會(huì)匹配所有未被其他路由模式匹配的請(qǐng)求。

func main() {
 mx := http.NewServeMux()

 mx.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
  fmt.Fprintln(writer, request.URL.EscapedPath())
 })

 http.ListenAndServe(":8009", mx)
}
$ curl 127.0.0.1:8009/abc
/abc

2、如果只注冊(cè)了一個(gè)子樹(shù)路徑(/結(jié)尾)并且請(qǐng)求URL沒(méi)有/結(jié)尾,ServeMux會(huì)返回重定向。如果再增加一個(gè)沒(méi)有/結(jié)尾的模式的話(huà),就會(huì)精確匹配,也就不會(huì)有這種行為了

例如我們只注冊(cè)了子路徑/abc/,服務(wù)器會(huì)自動(dòng)將/abc請(qǐng)求重定向?yàn)?code>/abc/。

func main() {
 mx := http.NewServeMux()
 mx.HandleFunc("/abc/", func(writer http.ResponseWriter, request *http.Request) {
  fmt.Fprintln(writer, request.URL.EscapedPath())
 })
 http.ListenAndServe(":8009", mx)
}
$ curl -v 127.0.0.1:8009/abc
*   Trying 127.0.0.1:8009...
* Connected to 127.0.0.1 (127.0.0.1) port 8009 (#0)
> GET /abc HTTP/1.1
> Host: 127.0.0.1:8009
> User-Agent: curl/7.79.1
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Content-Type: text/html; charset=utf-8
< Location: /abc/
< Date: Thu, 10 Nov 2022 15:30:13 GMT
< Content-Length: 40
< 
<a href="/abc/" rel="external nofollow"   >Moved Permanently</a>.

* Connection #0 to host 127.0.0.1 left intact

如果我們不想讓服務(wù)器自動(dòng)重定向的話(huà),只需要再添加一個(gè)/abc模式就好了

func main() {
 mx := http.NewServeMux()

 mx.HandleFunc("/abc/", func(writer http.ResponseWriter, request *http.Request) {
  fmt.Fprintln(writer, request.URL.EscapedPath())
 })

 mx.HandleFunc("/abc", func(writer http.ResponseWriter, request *http.Request) {
  fmt.Fprintln(writer, request.URL.EscapedPath())
 })

 http.ListenAndServe(":8009", mx)
}
$ curl  127.0.0.1:8009/abc 
/abc

域名匹配(Host-specific patterns)

ServeMux 還支持根據(jù)主機(jī)名精確匹配,匹配時(shí)會(huì)嚴(yán)格匹配host,path的匹配則還遵循上面的原則

?? 注意:

有域名的優(yōu)先級(jí)會(huì)更高,所以可以注冊(cè)一個(gè)帶域名的路徑和不帶域名的路徑

func main() {
 mx := http.NewServeMux()

 mx.HandleFunc("example01.com/abc/",
  func(writer http.ResponseWriter, request *http.Request) {
   fmt.Fprintln(writer, request.Host, request.URL.EscapedPath())
  })

 mx.HandleFunc("/abc/", func(writer http.ResponseWriter, request *http.Request) {
  fmt.Fprintln(writer, request.Host, request.URL.EscapedPath())
 })

 http.ListenAndServe(":8009", mx)
}

example01.com會(huì)匹配第一個(gè)handler,其他域名則匹配第二個(gè)

$ curl -H 'HOST:example01.com'  127.0.0.1:8009/abc/
example01.com /abc/

$ curl -H 'HOST:example02.com'  127.0.0.1:8009/abc 
example02.com /abc

Method和路徑參數(shù)匹配(method, path specificity patterns)

最新的特性還在討論中,大致的patterns會(huì)像下面這樣

https://github.com/golang/go/discussions/60227 

/item/
POST /item/{user}
/item/{user}
/item/{user}/{id}
/item/{$}
POST alt.com/item/{user}

以上就是Go標(biāo)準(zhǔn)庫(kù)-ServeMux的使用與模式匹配深入探究的詳細(xì)內(nèi)容,更多關(guān)于Go ServeMux模式匹配的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • golang進(jìn)行簡(jiǎn)單權(quán)限認(rèn)證的實(shí)現(xiàn)

    golang進(jìn)行簡(jiǎn)單權(quán)限認(rèn)證的實(shí)現(xiàn)

    本文主要介紹了golang簡(jiǎn)單權(quán)限認(rèn)證的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • go?sync?Waitgroup數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)基本操作詳解

    go?sync?Waitgroup數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)基本操作詳解

    這篇文章主要為大家介紹了go?sync?Waitgroup數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)基本操作詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • Ubuntu18.04 LTS搭建GO語(yǔ)言開(kāi)發(fā)環(huán)境過(guò)程解析

    Ubuntu18.04 LTS搭建GO語(yǔ)言開(kāi)發(fā)環(huán)境過(guò)程解析

    這篇文章主要介紹了Ubuntu18.04 LTS搭建GO語(yǔ)言開(kāi)發(fā)環(huán)境過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • 從零封裝Gin框架及項(xiàng)目初始化教程

    從零封裝Gin框架及項(xiàng)目初始化教程

    這篇文章主要為大家介紹了從零封裝Gin框架及項(xiàng)目的初始化教程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Golang結(jié)構(gòu)化日志包log/slog的使用詳解

    Golang結(jié)構(gòu)化日志包log/slog的使用詳解

    官方提供的用于打印日志的包是標(biāo)準(zhǔn)庫(kù)中的 log 包,該包雖然被廣泛使用,但是缺點(diǎn)也很多,所以Go 1.21新增的 log/slog 完美解決了以上問(wèn)題,下面我們就來(lái)看看log/slog包的使用吧
    2023-09-09
  • 詳解Go?sync?同步原語(yǔ)

    詳解Go?sync?同步原語(yǔ)

    Go?中不僅有?channel?這種?CSP?同步機(jī)制,還有?sync.Mutex、sync.WaitGroup?等比較原始的同步原語(yǔ),使用它們,可以更靈活的控制數(shù)據(jù)同步和多協(xié)程并發(fā),這篇文章主要介紹了Go?sync?同步原語(yǔ),需要的朋友可以參考下
    2023-12-12
  • go語(yǔ)言入門(mén)環(huán)境搭建及GoLand安裝教程詳解

    go語(yǔ)言入門(mén)環(huán)境搭建及GoLand安裝教程詳解

    這篇文章主要介紹了go語(yǔ)言入門(mén)環(huán)境搭建及GoLand安裝教程詳解,需要的朋友可以參考下
    2020-12-12
  • Go語(yǔ)言原子操作atomic的使用

    Go語(yǔ)言原子操作atomic的使用

    本文介紹了Go語(yǔ)言原子操作的使用方法,原子操作是一種無(wú)鎖的技術(shù),可通過(guò)CPU指令實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-10-10
  • go語(yǔ)言反射的基礎(chǔ)教程示例

    go語(yǔ)言反射的基礎(chǔ)教程示例

    這篇文章主要為大家介紹了go語(yǔ)言反射的基礎(chǔ)教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • omitempty在go中的使用方式

    omitempty在go中的使用方式

    在Go語(yǔ)言編程中,`omitempty`標(biāo)記用于JSON編解碼過(guò)程中控制字段是否被包含,當(dāng)結(jié)構(gòu)體字段標(biāo)記為`omitempty`且字段值為空時(shí),該字段不會(huì)出現(xiàn)在生成的JSON中,有助于優(yōu)化JSON結(jié)構(gòu)和減小數(shù)據(jù)體積,通過(guò)具體示例解釋了`omitempty`的工作機(jī)制和實(shí)際效果
    2024-09-09

最新評(píng)論