我们知道 Python Requests库 中的 Session 模块有连接池和会话管理的功能,比如请求一个登录接口后,会自动处理 response 中的 set-cookie,下次再请求时会自动把 cookie 带上。但最近出现了一个诡异的事情,cookie 没有自动带上,导致请求 403。

一开始怀疑是登录接口错误了,没有 set-cookie,但抓包发现 response header 中有 set-cookie,打印请求的 response.cookies 也有需要的 cookie。又怀疑是 set-cookie 的格式不对或者其它问题,但用浏览器实际跑了下流程,发现系统一切正常,那基本就是 requests 库的问题了。

没办法,只能 debug 了,单步调试了几轮,基本了解了 requests 的处理方式,首先把请求参数转变为 Request 对象,然后对使用 prepare_request 对 Request 进行预处理,其中有一步 merge_cookies 的操作(还有各种其它处理),把传入的 cookies 和 self.cookies merge 到 RequestsCookieJar 对象上去,这一步也没啥问题,merged_cookies 变量也是对的。后续将预处理过的请求,通过内置的 http adapter 发送出去。http adapter 底层是通过 urllib3.poolmanager 获取到 urllib3.connectionpool 连接(这里是连接池的核心部分),再通过 conn.urlopen 实际发送请求。虽然跟踪了解到了整个请求逻辑,但最终发出的请求还是没有带上需要的 cookie。

问题定位一度陷入僵局,只能再回顾上面的流程,cookie 肯定就是在 merged_cookies 和 conn.urlopen 之间没的,再仔细观察发现,conn.urlopen 请求参数里面压根没有 cookie 字段。

1

2

3

4

5

6

7

8

9

10

11

12

13 # :param request: The :class:`PreparedRequest ` being sent.

resp=conn.urlopen(

method=request.method,

url=url,

body=request.body,

headers=request.headers,

redirect=False,

assert_same_host=False,

preload_content=False,

decode_content=False,

retries=self.max_retries,

timeout=timeout

)

查阅资料发现,urllib3 的作者说,连接池只处理底层连接,cookie 跟踪等事情应该上层来做。大胆猜测,那 cookie 应该是放在 header 里了,往前捣看看 request.headers 是怎么变动的(此时里面的 Cookie 字段确实不正确)。

再走查代码发现 prepare_request 里面是调用了 PreparedRequest.prepare,其中有一步 prepare_cookies,主要是调用了 cookielib.CookieJar.add_cookie_header 最终将 cookie 放到了 self.headers['Cookie']。但里面有个 request.has_header("Cookie") 的判断,header 中没有 Cookie 字段才会放,不知道为什么这么考虑(最新版 3.8 还是这样),估计是 merge cookie 比较麻烦,但问题确实就出在这里,这次请求之前,Requests Session 已经直接通过 headers['Cookie'] 设置了 cookie。复现代码(修改自官方示例):

1

2

3

4

5

6

7

8

9

10 importrequests

s=requests.Session()

s.headers.update({

'Cookie':'k=v'

})

s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')

r=s.get('https://httpbin.org/cookies')

print(r.text)

# {"cookies":{"k":"v"}}

虽然找到了问题的原因,但又不好解决,总不能不让直接操作 headers['Cookie'] 吧,先不说无法限制使用者,而且之前的代码已经这样做了,改动量非常之大。不过好在,现在自己用的框架是在 Requests Session 上封装了一层,操作 header 都是调用的统一的 update_headers 方法:

1

2

3

4

5

6 defupdate_headers(self,headers):

"""

更新当前会话的header

:param headers: header字典

"""

self.headers.update(headers)

对 headers['Cookie'] 的操作拦截一下,变成对 cookies 的操作:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15 defupdate_headers(self,headers):

"""

更新当前会话的header

:param headers: header字典

"""

forheader_key,header_valueinheaders.items:

ifheader_key=='Cookie'orheader_key=='cookie':

c=Cookie.SimpleCookie()

c.load(header_value)

cookies={}

forkey,morselinc.items():

cookies[key]=morsel.value

requests.utils.add_dict_to_cookiejar(self.cookies,cookies)

delheaders[header_key]

self.headers.update(headers)

这样即不用改之前的调用方代码,也防止了后人掉坑。

参考资料

python requests session刷新_Python Requests Session set-cookie不生效的坑相关推荐

  1. python session模块_Python requests模块session代码实例

    http协议本身是无状态的,为了让请求之间保持状态,有了session和cookie机制.requests也提供了相应的方法去操纵它们. requests中的session对象能够让我们跨http请求 ...

  2. python requests 代理超时_python requests 超时与重试

    一 源起: requests模块作为python爬虫方向的基础模块实际上在日常实际工作中也会涉及到,比如用requests向对方接口url发送POST请求进行推送数据,使用GET请求拉取数据. 但是这 ...

  3. python requests是什么_python requests库学习

    Requests python的request库官方介绍就是让HTTP服务人类,所以从这点我们就可以知道request库是为了让我们更加方便的进行http相关的各种操作 我们学习request有什么用 ...

  4. 工信部python证书多少钱_python requests SSL证书问题

    错误信息如下: requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'tls_process_ser ...

  5. python绘制蚊香形_Python requests发送post请求的一些疑点

    前言 在Python爬虫中,使用requests发送请求,访问指定网站,是常见的做法.一般是发送GET请求或者POST请求,对于GET请求没有什么好说的,而发送POST请求,有很多朋友不是很清楚,主要 ...

  6. python requests cookies请求_python+requests实现接口测试 - cookies的使用

    在很多时候,发送请求后,服务端会对发送请求方进行身份识别,如果请求中缺少识别信息或存在错误的识别信息, 会造成识别失败. 如一些需要用户登录以后才能访问的页面. import requests mya ...

  7. python自动点赞软件_python requests 简单实现易班登录,自动点赞,评论,发表

    小编能力有限,本文纯属瞎编,如有雷同,你去打辅导员涩 一.前戏 有个操蛋,操蛋,操蛋的辅导员促使小编成长,原因:易班需要活跃度,辅导员安排班上每个人必须去易班上 写文章,写评论,发投票...  我觉得 ...

  8. python requests请求方式_Python Requests库使用2:请求方法

    GitHub API HTTP verbs Where possible, API v3 strives to use appropriate HTTP verbs for each action. ...

  9. python requests超时时间_python - requests 库 使用过程中timeout值最大可设值?

    问 题 请问 requests 库 使用过程中timeout错误的默认时间是多长呢? 查看源码 理论上 timeout值可以任意设? 默认 timeout 值 是怎么来的呢? 如果我想设一个比较大的t ...

最新文章

  1. ArduinoYun教程之通过网络为Arduino Yun编程
  2. 【NLP】四万字全面详解 | 深度学习中的注意力机制(四,完结篇)
  3. HttpClient的几个实现类
  4. Struts2中 Path (getContextPath与basePath)
  5. 配置mysql环境变量
  6. python classmethod函数_在python中使用与instance和classmethod相同的函数
  7. Daily Scrum M2 11-5
  8. 是否可以在网络共享磁盘上创建数据库?
  9. 【天梯选拔月赛】寻宝路线(dp)
  10. kappa一致性检验教程_Kappa一致性分析
  11. 点击进入我的QQ空间
  12. 以过来人经验---分享从学生--工程师之--怎么写好一份从事技术工作的简历及面试技巧(以嵌入式为例)(中)
  13. 计算机英语教学设计反思,小学五年级英语教学设计与反思
  14. JVM-SandBox使用入门
  15. Linux 安全缓解机制总结
  16. 总价加激励费用合同计算
  17. 视频中为什么需要这么多的颜色空间?
  18. Lenovo Y750 7-15IMH05 LA-J561P Rev 1.0笔记本原理图
  19. 卸载流氓软件/删除顽固文件教程
  20. 硬盘柱面损坏怎么办_硬盘有坏道就不能用了吗?别再吃哑巴亏了,今天跟人人再说一次...

热门文章

  1. Matlab高光谱样本相关性分析
  2. Leetcode--152. 乘积最大子数组(java)
  3. MYSQL--一条SQL更新语句是如何执行的?
  4. Leetcode--300. 最长上升子序列
  5. linux java amr转mp3_本工具用于将微信语音 amr 格式转换为 mp3 格式以便在 html5 的 audio 标签中进行播放...
  6. php mysql会员注册_PHP实现会员注册系统
  7. mongodb 监听不到端口_干货|MongoDB简单操作和通过python进行操作
  8. 查看ie保存的表单_小学信息技术gt;搜索保存网页教师资格证面试模板
  9. centos jupyter 安装_centos7安装 jupyter
  10. CompletableFuture详解~supplyAsync