go-zero讀取請求體出現(xiàn)EOF錯誤的解決方法
前言
最近自己在搭 go-zero 的腳手架,遇到一個問題,原先的一個 post 請求是執(zhí)行成功,當(dāng)我添加了一個過濾器之后執(zhí)行該請求就會報錯請求體讀取 EOF 錯誤,我感到有點奇怪,為什么過濾器中的邏輯會影響到后續(xù)的請求呢?在此記錄下這次的坑。
問題分析
先上結(jié)論,這是由于 go 中 http.Request.Body 請求體是一個流,它只能被讀取一次,假如你在過濾器已經(jīng)進(jìn)行過流的讀取,那么在后續(xù)的請求中就讀取不到了。
示例的請求邏輯是這樣,當(dāng)請求到達(dá)后臺時,先經(jīng)過過濾器檢查請求頭中是否攜帶 token,否則則請求失敗,成功則繼續(xù) post 請求邏輯,本次的 post 請求和過濾器只是做示例使用,邏輯很簡單,過濾器中的邏輯就是去獲取請求 header 中 token 字段,如果這個字段為空,則請求失敗,代碼示例如下:
func tokenFilter(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
type Request struct {
Token string `header:"token"`
}
var req Request
err := httpx.Parse(r, &req)
if err != nil || req.Token == "" {
resp, _ := utils.ToJsonString(models.ErrorResponseWithCode(http.StatusUnauthorized, "token required"))
routers.HttpError(w, http.StatusUnauthorized, resp)
return
}
next(w, r)
}
}
按照官方文檔推薦,在過濾器我使用了 httpx.Parse(r, &req) 獲取請求體數(shù)據(jù),導(dǎo)致后續(xù) post 請求邏輯讀取請求體失敗,也就是說,這個方法中會消耗掉請求體流的數(shù)據(jù),查看源碼可以發(fā)現(xiàn),這個方法是會讀取請求中的 path,form,header,body 數(shù)據(jù),賦值到我們的 struct 中:
func Parse(r *http.Request, v any) error {
kind := mapping.Deref(reflect.TypeOf(v)).Kind()
if kind != reflect.Array && kind != reflect.Slice {
if err := ParsePath(r, v); err != nil {
return err
}
if err := ParseForm(r, v); err != nil {
return err
}
if err := ParseHeaders(r, v); err != nil {
return err
}
}
if err := ParseJsonBody(r, v); err != nil {
return err
}
if valid, ok := v.(validation.Validator); ok {
return valid.Validate()
} else if val := validator.Load(); val != nil {
return val.(Validator).Validate(r, v)
}
return nil
}
繼續(xù)往下查看源碼可以發(fā)現(xiàn),其中的 ParseForm 方法和 ParseJsonBody 方法就會消耗掉請求體流的數(shù)據(jù),ParsePath 方法 ParseHeaders 方法則不會,而在這個過濾器中,我們只需要獲取 header 的數(shù)據(jù),body 的數(shù)據(jù)需要由后續(xù)邏輯獲取,所以在這里需要修改過濾只獲取 header 數(shù)據(jù)的方法,如果需要的是 path 數(shù)據(jù)也是同樣的道理,修改后的過濾器:
func tokenFilter(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
type Request struct {
Token string `header:"token"`
}
var req Request
err := httpx.ParseHeaders(r, &req)
if err != nil || req.Token == "" {
resp, _ := utils.ToJsonString(models.ErrorResponseWithCode(http.StatusUnauthorized, "token required"))
routers.HttpError(w, http.StatusUnauthorized, resp)
return
}
next(w, r)
}
}
修改后后續(xù)節(jié)點即可正常獲取請求體數(shù)據(jù)。
完整示例代碼請參考:igolang
到此這篇關(guān)于go-zero讀取請求體出現(xiàn)EOF錯誤的解決方法的文章就介紹到這了,更多相關(guān)解決go-zero讀取請求體出現(xiàn)EOF錯誤內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang的HTTP基本認(rèn)證機(jī)制實例詳解
這篇文章主要介紹了golang的HTTP基本認(rèn)證機(jī)制,結(jié)合實例形式較為詳細(xì)的分析了HTTP請求響應(yīng)的過程及認(rèn)證機(jī)制實現(xiàn)技巧,需要的朋友可以參考下2016-07-07
Golang 關(guān)于Gin框架請求參數(shù)的獲取方法
Gin是Go語言的Web框架,提供路由和中間件支持,本文介紹如何使用Gin獲取HTTP請求參數(shù),包括URLPath參數(shù)、URLQuery參數(shù)、HTTPBody參數(shù)和Header參數(shù),詳解直接獲取和綁定到結(jié)構(gòu)體兩種方法,幫助開發(fā)者高效處理Web請求2024-10-10
Go項目實現(xiàn)優(yōu)雅關(guān)機(jī)與平滑重啟功能
無論是優(yōu)雅關(guān)機(jī)還是優(yōu)雅重啟歸根結(jié)底都是通過監(jiān)聽特定系統(tǒng)信號,然后執(zhí)行一定的邏輯處理保障當(dāng)前系統(tǒng)正在處理的請求被正常處理后再關(guān)閉當(dāng)前進(jìn)程,這篇文章主要介紹了Go實現(xiàn)優(yōu)雅關(guān)機(jī)與平滑重啟 ,需要的朋友可以參考下2022-10-10
Golang調(diào)用FFmpeg轉(zhuǎn)換視頻流的實現(xiàn)
本文主要介紹了Golang調(diào)用FFmpeg轉(zhuǎn)換視頻流,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02
在Go語言單元測試中解決HTTP網(wǎng)絡(luò)依賴問題
在 Go 語言中,我們需要找到一種可靠的方法來測試 HTTP 請求和響應(yīng),本文將探討在 Go 中進(jìn)行 HTTP 應(yīng)用測試時,如何解決應(yīng)用程序的依賴問題,以確保我們能夠編寫出可靠的測試用例,需要的朋友可以參考下2023-07-07
Go 通過結(jié)構(gòu)struct實現(xiàn)接口interface的問題
這篇文章主要介紹了Go 通過結(jié)構(gòu)struct實現(xiàn)接口interface的問題,本文通過示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-10-10

