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

