最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

引言

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

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

當(dāng)你按如下方法注冊(cè)兩個(gè)路由的時(shí)候,bug會(huì)發(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()

上面的代碼會(huì)報(bào)錯(cuò):

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

分析

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

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

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

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

參考gin項(xiàng)目的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ù),最后都會(huì)調(diào)用到上面的方法。

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

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

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

沒(méi)錯(cuò),是所有,包括后面的/,比如html/group1/page1.html,也就是說(shuō)可以通過(guò)filepath訪問(wèn)到子目錄。

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

實(shí)際上是/html/group1/page1.html

catchAll通配符會(huì)嘗試向前多匹配一個(gè)/,如果你的路由中沒(méi)有這個(gè)/,會(huì)報(bào)錯(cuò)。

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

你可能會(huì)覺(jué)得報(bào)錯(cuò)是對(duì)的啊,那么你需要注意分清報(bào)錯(cuò)和bug產(chǎn)生的panic。

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

我說(shuō)的報(bào)錯(cuò)產(chǎn)生在panic("no / before catch-all in path '" + fullPath + "'")。

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

簡(jiǎn)單處理的話,這里應(yīng)該對(duì)i的值進(jìn)行判斷,然后主動(dòng)panic拋出可以讓人領(lǐng)悟的報(bào)錯(cuò)。

當(dāng)然,為了解決這個(gè)問(wèn)題本身,可以將上面的代碼修改為:

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

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

勘誤

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

實(shí)際上這個(gè)錯(cuò)誤發(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長(zhǎng)度實(shí)際為0,但這里卻默認(rèn)children有內(nèi)容。

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

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

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

相關(guān)文章

  • Golang中crypto/ecdsa庫(kù)實(shí)現(xiàn)數(shù)字簽名和驗(yàn)證

    Golang中crypto/ecdsa庫(kù)實(shí)現(xiàn)數(shù)字簽名和驗(yàn)證

    本文主要介紹了Golang中crypto/ecdsa庫(kù)實(shí)現(xiàn)數(shù)字簽名和驗(yàn)證,將從ECDSA的基本原理出發(fā),詳細(xì)解析如何在Go語(yǔ)言中實(shí)現(xiàn)數(shù)字簽名和驗(yàn)證,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • 基于go微服務(wù)效率工具goctl深度解析

    基于go微服務(wù)效率工具goctl深度解析

    這篇文章主要為大家介紹了基于go微服務(wù)效率工具goctl深度解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Go使用緩存加速外部資源訪問(wèn)提高性能效率

    Go使用緩存加速外部資源訪問(wèn)提高性能效率

    緩存是架構(gòu)設(shè)計(jì)中的常用概念,本文基于Go實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的緩存組件,支持最基本的緩存操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • 解決電腦用GoLand太卡將VsCode定制成Go IDE步驟過(guò)程

    解決電腦用GoLand太卡將VsCode定制成Go IDE步驟過(guò)程

    這篇文章主要為大家介紹了解決電腦用GoLand太卡,將VsCode定制成Go IDE步驟過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Golang 語(yǔ)言控制并發(fā) Goroutine的方法

    Golang 語(yǔ)言控制并發(fā) Goroutine的方法

    本文我們介紹了不同場(chǎng)景中分別適合哪種控制并發(fā) goroutine 的方式,其中,channel 適合控制少量 并發(fā) goroutine,WaitGroup 適合控制一組并發(fā) goroutine,而 context 適合控制多級(jí)并發(fā) goroutine,感興趣的朋友跟隨小編一起看看吧
    2021-06-06
  • 淺談Go連接池的設(shè)計(jì)與實(shí)現(xiàn)

    淺談Go連接池的設(shè)計(jì)與實(shí)現(xiàn)

    本文主要介紹了淺談Go連接池的設(shè)計(jì)與實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Go與C語(yǔ)言的互操作實(shí)現(xiàn)

    Go與C語(yǔ)言的互操作實(shí)現(xiàn)

    在Go與C語(yǔ)言互操作方面,Go更是提供了強(qiáng)大的支持。尤其是在Go中使用C,你甚至可以直接在Go源文件中編寫(xiě)C代碼,本文就詳細(xì)的介紹一下如何使用,感興趣的可以了解一下
    2021-12-12
  • Golang安裝和使用protocol-buffer流程介紹

    Golang安裝和使用protocol-buffer流程介紹

    這篇文章主要介紹了Golang安裝和使用protocol-buffer過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-09-09
  • Golang之sync.Pool對(duì)象池對(duì)象重用機(jī)制總結(jié)

    Golang之sync.Pool對(duì)象池對(duì)象重用機(jī)制總結(jié)

    這篇文章主要對(duì)Golang的sync.Pool對(duì)象池對(duì)象重用機(jī)制做了一個(gè)總結(jié),文中有相關(guān)的代碼示例和圖解,具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-07-07
  • 如何用go操作iptables和ipset設(shè)置黑白名單

    如何用go操作iptables和ipset設(shè)置黑白名單

    這篇文章主要介紹了如何用go操作iptables和ipset設(shè)置黑白名單問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-06-06

最新評(píng)論

阳谷县| 林周县| 都江堰市| 南投市| 如东县| 保定市| 崇明县| 西城区| 赞皇县| 刚察县| 和政县| 九龙县| 合阳县| 汝南县| 巍山| 板桥市| 温宿县| 淳化县| 邵东县| 江口县| 宝山区| 连平县| 大庆市| 长春市| 景洪市| 连云港市| 阜康市| 延津县| 布尔津县| 博爱县| 祥云县| 平定县| 梁平县| 万荣县| 宁波市| 清徐县| 广河县| 土默特右旗| 五常市| 灵武市| 吉林市|