
本文详解 requests 库中 r.history 为空的原因及解决方案,重点说明服务端重定向方式(如 Flask 的 redirect())与客户端 JavaScript 跳转的本质区别,并提供可运行的修复代码与关键配置说明。
本文详解 `requests` 库中 `r.history` 为空的原因及解决方案,重点说明服务端重定向方式(如 flask 的 `redirect()`)与客户端 javascript 跳转的本质区别,并提供可运行的修复代码与关键配置说明。
在使用 Python 的 requests 库进行 HTTP 请求时,Response.history 是一个包含所有重定向响应对象的列表(按跳转顺序排列),但其生效需同时满足两个前提:服务端必须返回标准 HTTP 重定向状态码(如 301、302)并携带 Location 响应头,且客户端必须启用自动重定向机制(即 allow_redirects=True,该参数默认为 True,但显式声明更稳妥)。
你遇到的 r.history 为空,根本原因在于 webserver.py 中采用的是前端 JavaScript 跳转:
@app.route('/')
def index():
return '<script>location.href = "https://youtube.com"</script>'这段代码返回的是状态码 200 OK 的 HTML 页面,浏览器执行 <script> 后跳转,但 requests 作为纯 HTTP 客户端<strong>不会解析或执行 JavaScript,因此完全感知不到跳转行为——它只收到一个 200 响应,自然无历史记录。</script>
✅ 正确做法是使用 Flask 的 redirect() 函数,由服务端主动发起符合 RFC 规范的 HTTP 重定向:
# app.py(修正版)
from flask import Flask, redirect
app = Flask(__name__)
@app.route('/')
def index():
return redirect('https://python.org') # 返回 302 + Location: https://python.org
if __name__ == '__main__':
app.run('0.0.0.0', 80, debug=False) # 注意:生产环境勿用 debug=True 或绑定 0.0.0.0对应客户端请求代码也需规范书写(避免 URL 拼接错误,并显式启用重定向):
# req.py(推荐写法)
import requests
url = 'http://localhost:80' # ✅ 显式带上协议,避免拼接歧义
r = requests.get(url, allow_redirects=True) # ✅ 显式声明,增强可读性
print("最终到达 URL:", r.url) # 输出: https://python.org
print("重定向历史:", [resp.url for resp in r.history]) # 输出: ['http://localhost:80']
print("历史响应状态码:", [resp.status_code for resp in r.history]) # 如: [302]⚠️ 关键注意事项:
- URL 协议不可省略:requests.get('localhost:80') 会被解析为 http://localhost:80/,但若服务端监听 http:// 且未配置 HTTPS,则可能因协议不匹配导致连接失败;建议始终显式指定 http:// 或 https://。
- allow_redirects 默认为 True,但显式设置是最佳实践,尤其在调试或链路复杂时可避免隐式行为引发的困惑。
- Flask 的 redirect() 默认返回 302(临时重定向),如需永久重定向可传入 code=301 参数。
- 本地测试端口 80 需管理员权限(Linux/macOS 需 sudo,Windows 可能受限),开发阶段建议改用 port=5000 并同步更新客户端 URL。
总结:r.history 为空不是 requests 的 Bug,而是客户端与服务端交互方式不匹配所致。只有当服务端通过标准 HTTP 状态码和 Location 头驱动重定向时,requests 才能捕获完整跳转链。掌握这一机制,是构建可靠自动化爬虫、API 测试工具和微服务调用链的基础能力。










