写点什么

http 请求 redirect 的问题

作者:飞翔123
  • 2022 年 7 月 13 日
  • 本文字数:1445 字

    阅读完需:约 5 分钟

这两天在开发项目的时候遇到了一个问题,请求了一个 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 #gosetup302
复制代码


基本实现了。其实,在 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是官方的建议的设置
最终的代码实现应该是这样的。```bashfunc 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)}
复制代码


用户头像

飞翔123

关注

是多福多寿 2017.08.31 加入

awsf首都发生大

评论

发布
暂无评论
http请求redirect的问题_golang_飞翔123_InfoQ写作社区