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

Go?Gin框架路由相關(guān)bug分析

 更新時間:2023年12月14日 09:40:02   作者:cainmusic  
這篇文章主要為大家介紹了Go?Gin框架路由相關(guān)bug分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

注:本文原文有錯誤,原文不改動,但在結(jié)尾進行了勘誤,注意讀到文章結(jié)尾。

Gin相關(guān)版本v1.9.1

當你按如下方法注冊兩個路由的時候,bug會發(fā)生。

r := gin.Default()
    r.GET("/static/", func(c *gin.Context) { c.String(200, "static") })
    r.GET("/static/*file", func(c *gin.Context) { c.String(200, "static file") })
    r.Run()

上面的代碼會報錯:

panic: runtime error: index out of range [0] with length 0

分析

雖然構(gòu)建路由樹的時候,Gin本身就會主動產(chǎn)生很多panic,但上面這個panic顯然是個意外。

這個bug由catchAll通配符的特異性導(dǎo)致。

catchAll通配符雖然寫作*paramname,但其構(gòu)建路由樹的時候會向前匹配一位/。

因為catchAll通配符通常是為了匹配路徑而存在的,catchAll通配符在gin中的經(jīng)典應(yīng)用就是配置靜態(tài)文件服務(wù)器。

參考gin項目的routergroup.go文件:

func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes {
    if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
        panic("URL parameters can not be used when serving a static folder")
    }
    handler := group.createStaticHandler(relativePath, fs)
    urlPattern := path.Join(relativePath, "/*filepath")
    // Register GET and HEAD handlers
    group.GET(urlPattern, handler)
    group.HEAD(urlPattern, handler)
    return group.returnObj()
}

一旦你使用Static相關(guān)函數(shù)配置靜態(tài)文件服務(wù),最后都會調(diào)用到上面的方法。

其中用你傳入的relativePath/*filepath組合為最終的url:relativePath/*filepath。

假如你傳入的路徑是/static,則最終url為/static/*filepath。

這個路由會匹配所有以/static/開頭的url,并將后面的所有內(nèi)容賦值到filepath。

沒錯,是所有,包括后面的/,比如html/group1/page1.html,也就是說可以通過filepath訪問到子目錄。

但上面描述的內(nèi)容實際上有一個錯誤,你以為filepath保存的內(nèi)容是html/group1/page1.html。

實際上是/html/group1/page1.html。

catchAll通配符會嘗試向前多匹配一個/,如果你的路由中沒有這個/,會報錯。

這個特性的特異之處導(dǎo)致gin中有一個bug,就是當你已經(jīng)注冊了/static/路由之后,再注冊/static/*file的時候,我們會在/static/節(jié)點上插入*filepath而不是/*filepath,這導(dǎo)致在程序判斷這是一個catchAll路由后,會去向前匹配一位/,這時i--后,變成了負數(shù),就導(dǎo)致了index out of range的錯誤。

你可能會覺得報錯是對的啊,那么你需要注意分清報錯和bug產(chǎn)生的panic。

i--
if path[i] != '/' {
    panic("no / before catch-all in path '" + fullPath + "'")
}

我說的報錯產(chǎn)生在panic("no / before catch-all in path '" + fullPath + "'")。

而bug產(chǎn)生的panic產(chǎn)生在i--變?yōu)樨摂?shù)后查詢if path[i] != '/'時。

簡單處理的話,這里應(yīng)該對i的值進行判斷,然后主動panic拋出可以讓人領(lǐng)悟的報錯。

當然,為了解決這個問題本身,可以將上面的代碼修改為:

r := gin.Default()
    r.GET("/static", func(c *gin.Context) { c.String(200, "static") })
    r.GET("/static/*file", func(c *gin.Context) { c.String(200, "static file") })
    r.Run()

第一個路由不要加末尾的/,就可以規(guī)避這個bug。

勘誤

前文提到panic: runtime error: index out of range [0] with length 0報錯,但這顯然不是index為負的報錯,是我之前預(yù)判i--為負時一廂情愿了。

實際上這個錯誤發(fā)生在i--的上面幾行:

if len(n.path) > 0 && n.path[len(n.path)-1] == '/' {
    pathSeg := strings.SplitN(n.children[0].path, "/", 2)[0]
    panic("catch-all wildcard '" + path +
        "' in new path '" + fullPath +
        "' conflicts with existing path segment '" + pathSeg +
        "' in existing prefix '" + n.path + pathSeg +
        "'")
}
// currently fixed width 1 for '/'
i--
if path[i] != '/' {
    panic("no / before catch-all in path '" + fullPath + "'")
}

這一行:pathSeg := strings.SplitN(n.children[0].path, "/", 2)[0]。

這里的children長度實際為0,但這里卻默認children有內(nèi)容。

看panic報錯的內(nèi)容:catch-all wildcard "path" in new path "fullPath" conflicts with existing path segment "pathSeg" in existing prefix "n.path" + "pathSeg"

大意上還是catchAll通配符和當前路徑?jīng)_突,但這里Gin默認此時n.children不為空的邏輯我還是沒太想明白。

以上就是Go Gin框架路由相關(guān)bug分析的詳細內(nèi)容,更多關(guān)于Go Gin框架路由bug的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解go程序如何在windows服務(wù)中開啟和關(guān)閉

    詳解go程序如何在windows服務(wù)中開啟和關(guān)閉

    這篇文章主要介紹了一個go程序,如何在windows服務(wù)中優(yōu)雅開啟和關(guān)閉,文中通過代碼示例和圖文講解的非常詳細,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-07-07
  • 如何利用Go語言實現(xiàn)LRU?Cache

    如何利用Go語言實現(xiàn)LRU?Cache

    這篇文章主要介紹了如何利用Go語言實現(xiàn)LRU?Cache,LRU是Least?Recently?Used的縮寫,是一種操作系統(tǒng)中常用的頁面置換算法,下面我們一起進入文章了解更多內(nèi)容吧,需要的朋友可以參考一下
    2022-03-03
  • Go基礎(chǔ)語法的使用

    Go基礎(chǔ)語法的使用

    本文主要介紹了Go基礎(chǔ)語法的使用,包括標識符、關(guān)鍵字、行分隔符、var關(guān)鍵字、:=運算符、空格、注釋、package、import、輸入輸出、運算符、條件控制、循環(huán)等,感興趣的可以了解一下
    2023-11-11
  • 如何在Go語言中靈活運用匿名函數(shù)和閉包

    如何在Go語言中靈活運用匿名函數(shù)和閉包

    這篇文章主要為大家介紹了如何在Go語言中靈活運用匿名函數(shù)和閉包實現(xiàn)實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • Go語言單線程運行也會有的并發(fā)問題解析

    Go語言單線程運行也會有的并發(fā)問題解析

    這篇文章主要為大家介紹了Go語言單線程運行的并發(fā)問題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • goFrame的gqueue與channe的區(qū)別

    goFrame的gqueue與channe的區(qū)別

    這篇文章主要介紹了goFrame的gqueue與channe的區(qū)別,channel的作用是用于go協(xié)程間的通信,goroutine和channel是支持高并發(fā)的重要組成部分,更多兩者詳細介紹需要的小伙伴可以參考下面文章內(nèi)容
    2022-06-06
  • 淺析Golang中調(diào)度器的關(guān)鍵機制與性能

    淺析Golang中調(diào)度器的關(guān)鍵機制與性能

    Golang的調(diào)度器是其并發(fā)模型的核心組件,負責(zé)管理Goroutine的調(diào)度和執(zhí)行,本文將從理論和代碼層面分析Golang調(diào)度器的關(guān)鍵機制,感興趣的可以了解下
    2025-03-03
  • Go unsafe 包的使用詳解

    Go unsafe 包的使用詳解

    這篇文章主要介紹了Go unsafe 包的使用詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • go語言之給定英語文章統(tǒng)計單詞數(shù)量(go語言小練習(xí))

    go語言之給定英語文章統(tǒng)計單詞數(shù)量(go語言小練習(xí))

    這篇文章給大家分享go語言小練習(xí)給定英語文章統(tǒng)計單詞數(shù)量,實現(xiàn)思路大概是利用go語言的map類型,以每個單詞作為關(guān)鍵字存儲數(shù)量信息,本文通過實例代碼給大家介紹的非常詳細,需要的朋友參考下吧
    2020-01-01
  • golang查看CPU使用率與內(nèi)存的方法詳解

    golang查看CPU使用率與內(nèi)存的方法詳解

    這篇文章主要給大家介紹了golang查看CPU使用率與內(nèi)存的方法,以及拓展介紹源碼里//go:指令,文中有詳細的代碼示例以及圖文介紹,需要的朋友可以參考下
    2023-10-10

最新評論