Go重寫http請求重定向的方法
一、背景
當(dāng)使用 Go 語言進(jìn)行 HTTP 請求時,默認(rèn)情況下,http.Client
會自動處理服務(wù)器返回的重定向響應(yīng)(3xx 狀態(tài)碼)。但有時候,我們可能需要在請求中禁止自動的重定向。本文將詳細(xì)介紹如何在 Go 中實(shí)現(xiàn)禁止 HTTP 請求的重定向、限制重定向次數(shù)以及添加自定義重定向策略。
二、默認(rèn)值
http.Client
的 CheckRedirect
字段是用于處理重定向策略的函數(shù),如果 CheckRedirect
不是 nil
,則客戶端會在遵循 HTTP 重定向之前調(diào)用它。參數(shù) req 和 via 是即將到來的請求和已經(jīng)發(fā)出的請求,最早發(fā)出的請求在前面。如果 CheckRedirect
返回錯誤,則 Client
的 Get
方法將返回前一個 Response(其 Body 關(guān)閉)和 CheckRedirect
的錯誤(包裝在 url.Error
),而不是繼續(xù)發(fā)出重定向請求。作為一種特殊情況,如果 CheckRedirect
返回 ErrUseLastResponse
,則返回的最新響應(yīng)體的 body, 且 body 未關(guān)閉,并返回 nil
錯誤。如果 CheckRedirect
為 nil
,則客戶端使用其默認(rèn)重定向策略,即在連續(xù) 10 個請求后停止。相關(guān)源碼如下,來自src/net/http/client.go
。
func defaultCheckRedirect(req *Request, via []*Request) error { if len(via) >= 10 { return errors.New("stopped after 10 redirects") } return nil }
三、禁止重定向
通過設(shè)置 http.Client
的 CheckRedirect
字段為一個為一個自定義的函數(shù),可以控制重定向的行為。這個函數(shù)接收一個 *http.Request
和一個 []*http.Request
參數(shù),前者代表當(dāng)前正在處理的請求,后者代表已經(jīng)請求的重定向請求鏈,返回 http.ErrUseLastResponse
錯誤,收到這個錯誤后,http.Client
不會再繼續(xù)重定向請求,并且返回一個 nil
錯誤給上游,如下:
func forbidRedirect(req *http.Request, via []*http.Request) (err error) { // 返回一個錯誤,表示不允許重定向 return http.ErrUseLastResponse }
如果 CheckRedirect
字段不設(shè)置值,或是設(shè)置 nil
值,都會采用上述的默認(rèn)函數(shù)defaultCheckRedirect
,進(jìn)行最多 10 重定向;如果返回的不是 http.ErrUseLastResponse
錯誤,那么該請求將會收到一個非 nil
的錯誤。
四、更改重定向次數(shù)
即更改對 []*http.Request
參數(shù)長度的限制即可,一定不能返回 http.ErrUseLastResponse
錯誤。
func limitRedirect(req *http.Request, via []*http.Request) error { // via 記錄了已經(jīng)請求的 url 個數(shù) if len(via) >= 3 { return errors.New("stopped after max redirects") } return nil }
五、自定義重定向策略
通過對重定向函數(shù)的重寫,添加一些自定義的邏輯,并將該函數(shù)其賦值給 http client 的CheckRedirect
,可以實(shí)現(xiàn)自定義重定向策略,其中 req.Response
參數(shù)表示導(dǎo)致該次重定向的返回。
func myRedirect(req *http.Request, via []*http.Request) error { // 限制重定向次數(shù) if len(via) >= 10 { return errors.New("stopped after 10 redirects") } if req == nil || req.URL == nil || req.Response == nil || !strings.HasPrefix(req.Response.Status, "3") { return http.ErrUseLastResponse } // 禁止重定向下載 apk 文件 if strings.HasSuffix(req.URL.Path, "apk") { return fmt.Errorf("invalid redirect url, path: %s", req.URL.Path) } // 限制重定向請求類型 contentType := req.Response.Header.Get("Content-Type") if strings.Contains(contentType, "octet-stream") { return fmt.Errorf("invalid redirect url, type: %s", contentType) } // 限制重定向請求體長度 contentLength := req.Response.Header.Get("Content-Length") if contentLength != "" { length, _ := strconv.Atoi(contentLength) if length > 1000 { return fmt.Errorf("invalid redirect url, len: %s", contentLength) } } // 限制重定向請求傳輸編碼 transferEncoding := req.Response.Header.Get("Transfer-Encoding") if strings.Contains(transferEncoding, "chunked") { return fmt.Errorf("invalid redirect url, encoding: %s", transferEncoding) } return http.ErrUseLastResponse }
六、完整示例
package main import ( "errors" "fmt" "io" "net/http" ) func forbidRedirect(req *http.Request, via []*http.Request) (err error) { // 返回一個錯誤,表示不允許重定向 return http.ErrUseLastResponse } func limitRedirect(req *http.Request, via []*http.Request) error { // via 記錄了已經(jīng)請求的 url 個數(shù) if len(via) >= 3 { return errors.New("stopped after max redirects") } return nil } func main() { // 創(chuàng)建一個自定義的 HTTP Client client := &http.Client{ CheckRedirect: forbidRedirect, } // 創(chuàng)建一個 GET 請求,該 url 一定要重定向 req, err := http.NewRequest("GET", "https://weibo.com", nil) if err != nil { fmt.Println("Error creating request:", err) return } // 使用自定義的 Client 發(fā)送請求 resp, err := client.Do(req) if err != nil { fmt.Println("Error sending request:", err) return } defer resp.Body.Close() fmt.Println("Response Status:", resp.Status) body, _ := io.ReadAll(resp.Body) fmt.Println("Response Body:", string(body)) }
七、總結(jié)
http.Client
的 CheckRedirect
字段是用于處理重定向策略的函數(shù),如果不賦值時就會采用默認(rèn)函數(shù),默認(rèn)最多重定向 10 次。我們可以通過重寫默認(rèn)函數(shù)來禁止重定向、改變重定向次數(shù)以及添加自定義的重定向過濾邏輯。
到此這篇關(guān)于Go重寫http請求重定向的方法的文章就介紹到這了,更多相關(guān)Go http請求重定向內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
go語言日志實(shí)現(xiàn)詳解(打印日志、日志寫入文件和日志切割)
golang內(nèi)置了log包,實(shí)現(xiàn)簡單的日志服務(wù),下面這篇文章主要給大家介紹了關(guān)于go語言日志實(shí)現(xiàn)(打印日志、日志寫入文件和日志切割)的相關(guān)資料,需要的朋友可以參考下2022-10-10go語言中的udp協(xié)議及TCP通訊實(shí)現(xiàn)示例
這篇文章主要為大家介紹了go語言中的udp協(xié)議及TCP通訊的實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04在golang中使用Sync.WaitGroup解決等待的問題
這篇文章主要介紹了在golang中使用Sync.WaitGroup解決等待的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04golang實(shí)現(xiàn)多協(xié)程下載文件(支持?jǐn)帱c(diǎn)續(xù)傳)
本文主要介紹了golang實(shí)現(xiàn)多協(xié)程下載文件,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11詳解Go語言中關(guān)于包導(dǎo)入必學(xué)的 8 個知識點(diǎn)
這篇文章主要介紹了詳解Go語言中關(guān)于包導(dǎo)入必學(xué)的 8 個知識點(diǎn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08