Golang development: http request redirection problem

I encountered a problem during the development of the project in the past two days. When I requested a URL, it would send 302 to another address. I just wanted to check whether this URL would do a 3XX redirection. As a result, the last request would be returned every time. The result of the jump. Later, I looked at the source code to understand the mechanism of the request jump

Implementation code

Look at the simple code implemented

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>

We know that entering http://www.qq.com in the browser will redirect 302 to https://www.qq.com. We can use curl to see the jump using 302.

But I just want to get the status code of the first response. I found that it couldn't be achieved, so I looked at the source code.

Why can http requests be redirected multiple times

Look at the client.Do source code implementation

607 err = c.checkRedirect(req, reqs)

In the context of the code, it can be seen that req is the request to be requested, and reqs has already requested the request

Mainly look at checkRedirect

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

You can see that if checkRedirect is set, checkRedirect is executed, and if not, defaultCheckRedirect is executed.

Look at defaultCheckRedirect again

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

You can see that you can redirect up to 10 times. If the jump is greater than 10, an error will be thrown to end the request.
In general, the process has been figured out. As long as you set checkRedirect to return error, you can theoretically achieve the purpose of only requesting once.

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

Basically realized.
In fact, there is a line of instructions above the CheckRedirect method,

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.

The Client.CheckRedirect hook can return ErrUseLastResponse to control how to handle redirection. If it returns, the next request is not sent, and the most recent response is returned and its body is not closed.

可以看到返回 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)
}

Guess you like

Origin blog.csdn.net/feifeixiang2835/article/details/109300948