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

golang多次讀取http request body的問題分析

 更新時間:2024年01月28日 10:31:39   作者:MinutkiBegut  
這篇文章主要給大家分析了golang多次讀取http request body的問題,文中通過代碼示例和圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下

問題起因

使用postman發(fā)送了一個http請求,對每個請求都有一個對應(yīng)的context:

type APIContext struct {
	Action   string
	ID       string
	Type     string
	Link     string
	Method   string
	Version  *APIVersion
	Request  *http.Request
	Response http.ResponseWriter
	...
}

其中Request成員變量是golang1.17.3版本http庫中定義的Request結(jié)構(gòu)(這里貼出部分成員變量):

type Request struct {
    Method string
    URL *url.URL
    Header Header
    Body io.ReadCloser
    GetBody func() (io.ReadCloser, error)
    Response *Response
    ctx context.Context
    ...
}

請求處理的代碼使用ReadAll方法讀取Request.Body,debug發(fā)現(xiàn)讀取出來的字節(jié)切片為空:

func ApiHandler() (error) {
    ...
    bodyBytes, err := ioutil.ReadAll(request.Request.Body)
    // fmt.Printf("bodyBytes: %+v", bodyBytes) 結(jié)果為[]
    if err != nil {
        ...
    }
    ...
}

問題探究

我把這個問題發(fā)給了gpt

在這里插入圖片描述

gpt回答說可能是由于Body已經(jīng)被讀取過一次,事實上,我的代碼之前確實使用過ReadBody方法讀取了一次:

func ApiHandler2() (error) {
    input, err := parse.ReadBody(request.Request)
    ...
}

這個parse.ReadBody是公司的庫代碼,在此不深入分析

出于好奇,我問了gpt官方庫中ioutil.ReadAll()方法能否多次讀取Request.Body

在這里插入圖片描述

gpt回答ReadAll()方法讀取了一次就會消耗掉Request.Body,不能再次讀取,并提供兩種方法再次讀?。?/p>

  • 將讀取的Request.Body緩存到一個變量bodyBytes(字節(jié)切片類型),后續(xù)需要讀取
  • 使用該變量使用ioutol.NopCloser方法寫回到Request.Body

問題溯源

來研究一下ioutil.ReadAll()源碼:

// ReadAll reads from r until an error or EOF and returns the data it read.
// A successful call returns err == nil, not err == EOF. Because ReadAll is
// defined to read from src until EOF, it does not treat an EOF from Read
// as an error to be reported.
func ReadAll(r Reader) ([]byte, error) {
	b := make([]byte, 0, 512)
	for {
		if len(b) == cap(b) {
			// Add more capacity (let append pick how much).
			b = append(b, 0)[:len(b)]
		}
		n, err := r.Read(b[len(b):cap(b)])
		b = b[:len(b)+n]
		if err != nil {
			if err == EOF {
				err = nil
			}
			return b, err
		}
	}
}

函數(shù)的作用是初始化一個字節(jié)切片緩沖區(qū),不斷調(diào)用Read方法讀取數(shù)據(jù),直到EOF為止

緩沖區(qū)b的初始大小只有512個字節(jié),如果緩沖區(qū)滿(len(b)==cap(b)),則向b添加一個0元素觸發(fā)切片的擴(kuò)容機(jī)制,并去掉添加的"0"元素([:len(b)]),之后一直讀取數(shù)據(jù),可能緩沖區(qū)又會滿,會繼續(xù)擴(kuò)容的操作,直到讀取到EOF

從對ReadAll()方法的分析可以得知,使用ReadAll函數(shù)處理數(shù)據(jù)時,內(nèi)存消耗隨著數(shù)據(jù)的增大而增加,處理較大數(shù)據(jù)時,會觸發(fā)多次擴(kuò)容機(jī)制,需要分配大量內(nèi)存。加載一個10M的文件,可能就需要50M的內(nèi)存分配

io.Reader 接口中的 Read 方法的定義如下:

type Reader interface {
    Read(p []byte) (n int, err error)
}

這個方法接收一個字節(jié)數(shù)組 p 作為參數(shù),返回兩個值,一個是 n 表示讀取的字節(jié)數(shù),另一個是 err 表示可能出現(xiàn)的錯誤。不同的數(shù)據(jù)源類型實現(xiàn)方式不同

Request.Body只能讀取一次的原因是因為,在第一次對其進(jìn)行讀取時,指針已經(jīng)移動到了 EOF(End Of File)位置,再次讀取時就無法再次從頭開始讀取了

題外話

關(guān)于ReadAll()方法消耗內(nèi)存的替代方案有兩種:

  • 使用io.ReadFile函數(shù)
  • 使用io.Copy函數(shù)

ReadFile函數(shù)定義如下:

func ReadFile(filename string) ([]byte, error){}

傳參為待加載文件的路徑,返回為文件的內(nèi)容

  • io.Copy會拷貝數(shù)據(jù),少于ReadAll的內(nèi)存消耗

以上就是golang多次讀取http request body的問題分析的詳細(xì)內(nèi)容,更多關(guān)于golang多次讀取http request body的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語言中循環(huán)與判斷的語法、用法與最佳實踐

    Go語言中循環(huán)與判斷的語法、用法與最佳實踐

    本文詳細(xì)介紹了Go語言的if條件判斷、for循環(huán)和switch語句的用法,包括基本語法、高級用法和實戰(zhàn)技巧,并指出了一些常見的錯誤和最佳實踐,通過本文,讀者可以掌握Go語言中的循環(huán)和條件判斷的核心用法,需要的朋友可以參考下
    2026-04-04
  • Go語言中一些不常見的命令參數(shù)詳解

    Go語言中一些不常見的命令參數(shù)詳解

    這篇文章主要給大家介紹了關(guān)于Go語言中一些不常見的命令參數(shù)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-12-12
  • 如何解決goland,idea全局搜索快捷鍵失效問題

    如何解決goland,idea全局搜索快捷鍵失效問題

    這篇文章主要介紹了如何解決goland,idea全局搜索快捷鍵失效問題,快捷鍵失效,可能是快捷鍵沖突,也或者是快捷鍵被修改成其他了。在settings下查看快捷鍵是否被修改,下文詳細(xì)介紹需要的朋友可以參考下
    2022-04-04
  • 一文徹底理解Golang閉包實現(xiàn)原理

    一文徹底理解Golang閉包實現(xiàn)原理

    閉包對于一個長期寫Java的開發(fā)者來說估計鮮有耳聞,光這名字感覺就有點"神秘莫測"。這篇文章的主要目的就是從編譯器的角度來分析閉包,徹底搞懂閉包的實現(xiàn)原理,需要的可以參考一下
    2022-10-10
  • Go語言使用組合的方式實現(xiàn)多繼承的方法

    Go語言使用組合的方式實現(xiàn)多繼承的方法

    這篇文章主要介紹了Go語言使用組合的方式實現(xiàn)多繼承的方法,實例分析了多繼承的原理與使用組合方式來實現(xiàn)多繼承的技巧,需要的朋友可以參考下
    2015-02-02
  • 使用Go語言判斷二叉樹是否對稱的方法小結(jié)

    使用Go語言判斷二叉樹是否對稱的方法小結(jié)

    二叉樹Binary Tree一種特殊的樹,是結(jié)點的一個有限集合,且所有結(jié)點最多有2個子結(jié)點,即度只能是0,1,2,判斷二叉樹是否對稱需比較左右子樹結(jié)構(gòu)與值,遞歸法直接對比子節(jié)點,迭代法用隊列模擬遞歸,本文通過代碼示例講解的非常詳細(xì),需要的朋友可以參考下
    2025-07-07
  • Golang實現(xiàn)HTTP編程請求和響應(yīng)

    Golang實現(xiàn)HTTP編程請求和響應(yīng)

    本文主要介紹了Golang實現(xiàn)HTTP編程請求和響應(yīng),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Go語言實現(xiàn)lru淘汰策略和超時過期

    Go語言實現(xiàn)lru淘汰策略和超時過期

    緩存的大小是有限的,當(dāng)添加數(shù)據(jù)發(fā)現(xiàn)剩余緩存不夠時,需要淘汰緩存中的部分?jǐn)?shù)據(jù),本文主要介紹了Go語言實現(xiàn)lru淘汰策略和超時過期,感興趣的可以了解一下
    2024-02-02
  • Golang操作sqlite3數(shù)據(jù)庫的詳細(xì)教程

    Golang操作sqlite3數(shù)據(jù)庫的詳細(xì)教程

    最近會使用到sqlite3,這里作個記錄,記性越來越差就是這樣,下面這篇文章主要給大家介紹了關(guān)于Golang操作sqlite3數(shù)據(jù)庫的詳細(xì)教程,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-04-04
  • Go語言實現(xiàn)可選參數(shù)的方法小結(jié)

    Go語言實現(xiàn)可選參數(shù)的方法小結(jié)

    這篇文章主要為大家詳細(xì)介紹了Go語言實現(xiàn)可選參數(shù)的一些常見方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-02-02

最新評論

太康县| 平远县| 睢宁县| 习水县| 沧源| 巨野县| 荃湾区| 无棣县| 古田县| 华容县| 屏山县| 贞丰县| 南溪县| 屏南县| 通化县| 龙陵县| 淄博市| 高碑店市| 海兴县| 海门市| 镇原县| 年辖:市辖区| 建湖县| 郯城县| 漳浦县| 翁牛特旗| 金乡县| 永吉县| 瑞丽市| 剑阁县| 厦门市| 迁西县| 崇义县| 南京市| 遂平县| 清河县| 和政县| 调兵山市| 龙泉市| 泰兴市| 彭阳县|