搭建正规网站,h5设计平台,企业网站建设的管理制度,公司做网站需要什么我们知道 Python Requests库 中的 Session 模块有连接池和会话管理的功能#xff0c;比如请求一个登录接口后#xff0c;会自动处理 response 中的 set-cookie#xff0c;下次再请求时会自动把 cookie 带上。但最近出现了一个诡异的事情#xff0c;cookie 没有自动带上比如请求一个登录接口后会自动处理 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 字段。12345678910111213 # :param request: The :class:PreparedRequest being sent.respconn.urlopen(methodrequest.method,urlurl,bodyrequest.body,headersrequest.headers,redirectFalse,assert_same_hostFalse,preload_contentFalse,decode_contentFalse,retriesself.max_retries,timeouttimeout)查阅资料发现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。复现代码(修改自官方示例)12345678910 importrequestssrequests.Session()s.headers.update({Cookie:kv})s.get(https://httpbin.org/cookies/set/sessioncookie/123456789)rs.get(https://httpbin.org/cookies)print(r.text)# {cookies:{k:v}}虽然找到了问题的原因但又不好解决总不能不让直接操作 headers[Cookie] 吧先不说无法限制使用者而且之前的代码已经这样做了改动量非常之大。不过好在现在自己用的框架是在 Requests Session 上封装了一层操作 header 都是调用的统一的 update_headers 方法123456 defupdate_headers(self,headers):更新当前会话的header:param headers: header字典self.headers.update(headers)对 headers[Cookie] 的操作拦截一下变成对 cookies 的操作123456789101112131415 defupdate_headers(self,headers):更新当前会话的header:param headers: header字典forheader_key,header_valueinheaders.items:ifheader_keyCookieorheader_keycookie:cCookie.SimpleCookie()c.load(header_value)cookies{}forkey,morselinc.items():cookies[key]morsel.valuerequests.utils.add_dict_to_cookiejar(self.cookies,cookies)delheaders[header_key]self.headers.update(headers)这样即不用改之前的调用方代码也防止了后人掉坑。参考资料