DEBUG.WIKI
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →
雨云;给项目一台云服务器
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →

Requests 的 URL 带 Basic 凭据后 Cookie 消失

Requests2.34.2配合CPython3.14.7时,URL userinfo可能进入Cookie域判断。改用干净HTTPS地址与独立auth参数,仍核对Cookie域、路径及认证边界。

Requests的Session里已经有目标域名的Cookie,普通URL能带上,改成 https://user:password@主机/ 后却只有Authorization,没有Cookie。先把“Basic认证成功”和“Cookie域匹配成功”分开看,两者经过的处理不同。

一个具体环境是Requests2.34.2、CPython3.14.7,Cookie 的域为 127.0.0.1、路径为 /,URL加入userinfo后匹配失效。这里讨论的是已有Cookie在请求准备阶段被遗漏,不是登录接口没有设置Cookie,也不表示所有域名、所有Cookie策略都会有相同结果。

URL里的凭据会进入Cookie主机判断

Requests的Cookie兼容层把请求URL交给标准库cookiejar。该CPython版本的request_host从URL netloc取主机再去端口,不会先单独剥离userinfo。于是域匹配可能拿到包含用户名、密码的主机字符串,与Cookie原来的域不相等。

与此同时,Requests还会提取URL凭据生成Basic认证头。服务器收到Authorization,不能反证Cookie也一定被发送。问题出现时应记录脱敏后的URL形状、Cookie域/路径/Secure属性与实际请求头是否存在,不记录Cookie值或Authorization内容。

去掉userinfo,单独提供Basic认证

对已经确认使用Basic认证的接口,保留干净的HTTPS URL,把认证交给auth参数。以下是请求准备示例,不发送网络请求;Session应来自应用原来管理的会话,其中已有正常获取、且范围正确的Cookie:

import os
import requests

request = requests.Request(
    'GET',
    'https://api.example.com/account',
    auth=(os.environ['API_USER'], os.environ['API_PASSWORD']),
)
prepared = session.prepare_request(request)

api.example.com/account是占位地址,必须使用实际获准接口;代码中的session是应用已有的Session对象,不能把示例域名换掉,却继续使用另一域名的Cookie。不要打印prepared.headers,里面可能同时含有认证与会话凭据。

实际发送时沿用原来的超时、TLS、代理和受控重定向约定。Basic凭据应仅发送给授权的HTTPS接收方;不要为了恢复Cookie把密码搬到query参数,也不手工拼接一个不受域/路径限制的Cookie头。

域和路径不正确时,分离认证也不会补出Cookie

检查Cookie是否过期、Secure是否要求HTTPS、域名或路径是否与目标一致。127.0.0.1与localhost不同,改写其中一个也会改变Cookie作用域;不能为了复现而同时换主机名,再把差异全归到userinfo。

若请求经过跨源跳转,还要逐跳检查认证边界,不能把第一跳的Cookie问题与后续有意删除Authorization混在一起。该处理只改变凭据的提供方式,不取消服务端任何一项认证要求。

用同一Session、同一目标主机与路径比较请求准备结果,再在获准的只读测试入口确认服务端识别的账号与会话。仅看HTTP200不足以证明身份一致,响应可能只是登录页。已有带密码的书签、脚本参数和日志也应按项目凭据流程处理,URL不再含密码不会自动清除旧记录。