golang開發:http請求redirect的問題


這兩天在開發項目的時候遇到了一個問題,請求了一個URL,它會302到另一個地址,本意上只是想檢查這個URL是否會做3XX的redirect跳轉,結果每次reqeust都會返回最后一跳的結果。后來就看了下源碼,了解下請求跳轉的機制

實現代碼

看下實現的簡單代碼

func main() {
	client := &http.Client{}
	url := "http://www.qq.com"
	reqest, err := http.NewRequest("GET", url, nil)
	if err != nil {
		panic(err)
	}
	response, _ := client.Do(reqest)
	fmt.Println(response.Status)
}

curl http://www.qq.com
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>stgw/1.3.12.4_1.13.5</center>
</body>
</html>

我們知道在瀏覽器里面輸入http://www.qq.com會302跳轉到https://www.qq.com。我們使用curl可以看到使用302的跳轉。

可是我只想獲取第一跳的的response 的狀態碼。發現沒法實現了,所以看了下源碼。

http請求為什么可以做到多次redirect

看了下 client.Do 源碼實現

607 err = c.checkRedirect(req, reqs)

代碼的上下文,可以看出 req是將要請求的request,reqs已經請求過的request

主要看下checkRedirect

func (c *Client) checkRedirect(req *Request, via []*Request) error {
	fn := c.CheckRedirect
	if fn == nil {
		fn = defaultCheckRedirect
	}
	return fn(req, via)
}

可以看到如果設置了checkRedirect就執行checkRedirect,如果沒有設置就執行 defaultCheckRedirect。

再看下 defaultCheckRedirect

func defaultCheckRedirect(req *Request, via []*Request) error {
	if len(via) >= 10 {
		return errors.New("stopped after 10 redirects")
	}
	return nil
}

可以看到最多可以redirect 10次,如果大於10的跳轉就拋出錯誤結束這次請求了。
大體上流程已經搞明白。只要設置checkRedirect返回error,理論上就能實現只請求一次的目的。

func main() {
	client := &http.Client{}
	url := "http://www.qq.com"
	reqest, err := http.NewRequest("GET", url, nil)
	if err != nil {
		panic(err)
	}
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		return fmt.Errorf("first response")
	}
	response, _ := client.Do(reqest)
	fmt.Println(response.StatusCode)
}

/private/var/folders/4h/lrsc4fyd12v9ctl31ggk5ckc0000gp/T/___go_build_main_go #gosetup
302

基本實現了。
其實,在CheckRedirect方法上面有一行說明,

ErrUseLastResponse can be returned by Client.CheckRedirect hooks to control how redirects are processed. If returned, the next request is not sent and the most recent response is returned with its body unclosed.

Client.CheckRedirect掛鈎可以返回ErrUseLastResponse,以控制如何處理重定向。 如果返回,則不發送下一個請求,並且返回最近的響應且其主體未關閉。

可以看到返回 ErrUseLastResponse是官方的建議的設置

最終的代碼實現應該是這樣的。

```bash
func main() {
	client := &http.Client{}
	url := "http://www.qq.com"
	reqest, err := http.NewRequest("GET", url, nil)
	if err != nil {
		panic(err)
	}
	client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
		return http.ErrUseLastResponse
	}
	response, _ := client.Do(reqest)
	fmt.Println(response.StatusCode)
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM