Go -- client 302 自动转 200 问题 cookie存储 模拟登陆问题

不久前用go写了个http client,去模拟某网站(*.com)的登录操作。网站的登录逻辑:1.验证登录账号和密码;2.下发token。此token通过cookie下发;3.redirect到主页(/)。主页对token进行校验,渲染、展示页面信息。简单调用http.DefaultClient.Do(request),并未获取到预期的response,问题究竟出在了什么地方。

net/http.Client 默认自动处理redirect

我们跟踪一下库代码,看一下详细的逻辑。通过函数名,为我们获得一个初步印象:对于“GET”、“HEAD”、“POST”、“PUT”请求,将进行自动重定向。至于“GET”和“HEAD”对于哪些status code进行重定向、“POST”和“PUT”方法又响应哪些status code的重定向呢?关键就在于doFollowingRedirects的第二个入参:shouldRedirectGet和shouldRedirectPost函数。

将case中的常量翻译一下,就是“HEAD”和“GET”方法,响应301、302、303和307;“POST”和“PUT”方法响应302和303。意味着redirect默认是自发执行的,为何登录跳转失败呢?问题出在了cookie上。默认重定向时,并不会保存上次response的cookie,自然不会携带相应的cookie去发起redirect后的请求。

redirect 携带cookie在http.Client中有一个Jar字段,用于存储(内存)cookies。

注释写得很清楚,如果此字段为空,client发起请求时,将不携带cookies且response返回的cookies将被忽略。CookieJar的定义位于net/http的jar.go中,是一个interface。

所谓CookieJar,直白点,就是一个cookie的存储,很自然提供两个方法:SetCookies和Cookies,分别用于set和get操作。net/http/cookiejar中给出了一个CookieJar的实现。

显然Jar中真正用来存储cookies的就是entries这一成员变量了,为一个双map结构。map的第一个key为域名后缀,按照pList(PublicSuffixList)指定的规则来获取;第二个key为cookie name、domain和path拼接而成的一个string。pList可以为空。

无须继续往下,我们已经知晓只要为client设置Jar字段,即可实现redirect的时候携带相应cookie的目的。

自此,问题得以解答。后面再罗嗦一点相关的东西。

jar 的 cookie 匹配规则

实例代码中,通过cookiejar.New(nil)初始化一个cookie jar,即Jar.pList为nil,使用默认的cookie匹配规则。Jar数据结构的介绍中,说明了pList将影响entries map的第一个key,具体的实现为jarKey这个函数。

PublicSuffixList是一个interface,当Jar中为指定此字段时,将采用默认的匹配规则:""作为key(假如域名为,key则为);否则将使用PublicSuffixList的实现类的规则来挑选key,中提供了一种实现,这里不再深究,感兴趣的同学,自行前去观看。

禁止 redirect如果不希望client代替我们做redirect,有什么办法呢?Client数据结构中设计了一个CheckRedirect的字段,此字段是一个函数引用。

从注释中,我们很容易获知禁止redirect的解决方法:CheckRedirect函数简单返回一个http.ErrUseLastResponse即可。这个埋点(CheckRedirect调用)发生在什么位置呢?调用链:http.Do -> c.doFollowingRedirect -> c.checkRedirect。

checkRedirect位于一个for循环中,循环次数由后端redirect的次数和最大允许的递归重试(默认10)次数共同决定。显然,当checkRedirect返回一个http.ErrUseLastResponse的错误后,redirect的循环正常退出。

如何禁止redirect回答完毕。checkRedirect函数,浅显易懂,就不再多介绍。贴出源代码,大家一起再来感受和膜拜一下库作者令人拍案叫绝的设计能力和注释的书写能力!

原文地址:https://www.cnblogs.com/mafeng/p/11663230.html