python requests session刷新_Python Requests Session set-cookie不生效的坑
我們知道 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不生效的坑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php ckeditor 配置,Lara
- 下一篇: postmapping注解_Swagge