[Go] 禁止 net/http 包中 http.Client 的自动重定向
Go 语言标准库的 net/http 包中的 http.Client 默认会自动跟随(follow)重定向,大多数时候,这种自动化的跟随是有意义的。比如:自动把 HTTP 连接重定向到 HTTPS 连接。 但是,也有很多时候这种自动重定向会带来麻烦,或是不必要。比如:常用的模拟 POST 登录方式。
常见的 POST 登录方式
- 浏览器
POST /login
- 服务器返回
302 Found
,并携带 Cookie 和新的登录后的页面/index
- 浏览器重新发起到
/index
的请求
如果直接使用 http.Post
并登录成功的话,最终的页面是/index
,中间的重定向相关的数据是拿不到的,包括 Cookie!
而我最近刚做一个命令行的路由器客户端,它就需要将上面过程中第二步返回的 Cookie 拿到,并用作后续 API 请求的验证。 所以,得想办法禁止 http.Client 的自动重定向。
http.Client 中的重定向
http.Client
中有一个跟重定向相关的字段CheckRedirect:
// CheckRedirect specifies the policy for handling redirects.
// If CheckRedirect is not nil, the client calls it before
// following an HTTP redirect. The arguments req and via are
// the upcoming request and the requests made already, oldest
// first. If CheckRedirect returns an error, the Client's Get
// method returns both the previous Response (with its Body
// closed) and CheckRedirect's error (wrapped in a url.Error)
// instead of issuing the Request req.
// As a special case, if CheckRedirect returns ErrUseLastResponse,
// then the most recent response is returned with its body
// unclosed, along with a nil error.
//
// If CheckRedirect is nil, the Client uses its default policy,
// which is to stop after 10 consecutive requests.
CheckRedirect func(req *Request, via []*Request) error
从注释来看,这是一个函数字段,用于指定处理重定向的策略:
-
如果这个字段不为空,Client将在每次重定向之前先调用它。如果这个函数返回了一个特殊的ErrUseLastResponse错误(Go1.7引入),那么将使用最近一次的请求响应作为返回;
// Sentinel error to let users select the // previous response, without closing its // body. See Issue 10069. if err == ErrUseLastResponse { return resp, nil }
-
如果这个字段为空,Client 将采用默认的重定向策略:将在最多连续重定向 10 次后停止;
如何禁止重定向
不使用默认的 http.Get
、http.Post
等方法,而是自定义一个带不重定向功能的 Client:
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
然后调用 client 的 client.Get
、client.Post
、client.Do
等方法即可。