在快速开发中,没有精力完善单元测试,但为了调试、验证,按网络连接的会话流程,写了测试用的python脚本。
脚本执行的过程是,
1、调用登录接口,获取cookie
2、使用数据接口时,在header中设置这个cookie,才能正常访问。
使用了requests包做http请求,很方便。
但在部署核心集群时遇到了问题:
由于限制使用外网,无法通过yum、easy_install来更新服务器、python依赖的操作.
好在python的内置库还有urllib2和urllib,可以替换requests,印象里调用过程差别不大。这样的改动成本,比手动安装依赖小。
改写
简单修改后,总是返回登录异常。
通过wireshark抓包,发现:
把post数据的字典,直接转换为字符串,发送请求就是上图的样子。
请求参数都挤在key里面,value是空的;要想正常的post数据字典,应该加上urllib.urlencode(data)。
连接值
登录鉴权发送正常了,数据接口请求还是失败。
打印鉴权请求返回的header,并没有cookie,获取不到cookie,就不能调用后面的接口。
于是我又对比了requests和urllib2 两者发送请求的异同,我发现,requests发送的headers里面,连接值为“keep-alive”,而urllib2发送连接值为“close”。
我以为这就是问题所在,查了大量修改header的连接值(Connection)的方法,答案却是无解。
这是因为,虽然urllib2保留了设置header参数的接口,但是对于连接值,是硬编码到内置代码里的,无论如何显式修改,实际的连接值只能是“close”。
urllib2如此设计的初衷,是为了避免一处bug,不细说了。不过对于一些场景,确实非常不便,比如用到长连接的FTP下载。
cookie
这些不便的场景里,其实不包括登录。
清醒的想一下,urllib2是个老古董,但也是纵横多年的python内置依赖,怎么可能一个简单的登录会话都完成不了?连接值只是控制http请求是长连接还是短连接,而和登录会话没有关系吧,毕竟我只是要获取cookie而已啊。
改变了思路,谷歌转而搜索“urllib2 登录”,很容易搜到现成代码。
原来,在urllib2,cookie的管理是分离的,需要引入cookielib,对urllib2加一些配置,登录行为后就可以会保存cookie,在之后的会话中默认自动在header中设置。
之前抓包过程中,我只看了登录的post请求,没有查看登录接口的返回,所以忽略了后面的关键线索。
而一个完整的登录请求会话,是“发送post请求”、“接收到客户端302跳转”、“发送get请求”、“接收到返回200”,只要看一下后续的请求和返回,就不会把问题定位到无关的连接值。
对urllib2做设置之后,整个会话就没有问题了。
搞定之后,觉得还是用requests更清新、友好,顺便熟悉了一下wireshark,收获不小。
重要的经验是,分析具体问题中,不要忘记常识,避免走到与真实问题无关的死胡同。
-END-
赞赏一下作者吧~
关注作者吧~
领取专属 10元无门槛券
私享最新 技术干货