levels of contents

requests 库中的 hooks 参数

requests 库中的 hooks 参数。

1. hooks 参数的作用

hooks 参数允许你在 HTTP 请求的特定生命周期事件前后执行自定义函数(称为 “钩子函数”)。这提供了一种强大的方式来拦截、修改或监控请求过程,而无需修改 requests 库本身的代码。
 
你可以把钩子想象成一个 “回调函数”,当请求达到某个特定阶段时,requests 会自动调用它。
 
常见的应用场景包括:
 
  • 请求前预处理:在请求发送之前修改请求头、请求参数或请求体。
  • 响应后处理:在获取到响应后,自动解析响应内容、处理错误、记录日志或提取特定数据。
  • 日志记录:记录所有发出的请求和收到的响应的详细信息,用于调试或审计。
  • 重试逻辑:当请求失败时(例如,遇到特定的状态码或网络错误),自动触发重试。
  • 性能监控:测量请求的耗时。

2. 如何使用 hooks 参数

hooks 参数接受一个字典,其中键是事件名称,值是一个或多个钩子函数。

2.1 常用的钩子事件

requests 主要支持以下几个钩子事件:
 
  • 'request': 在请求被发送之前调用。钩子函数接收 request 对象作为参数。
  • 'response': 在请求成功收到响应之后,并且在 requests 将响应返回给你之前调用。钩子函数接收 response 对象作为参数。
  • 'error': 在请求过程中发生异常时调用(例如,连接超时、DNS 错误等)。钩子函数接收 exception 对象作为参数。

2.2 钩子函数的签名

  • 对于 'request' 钩子:def hook_func(request, **kwargs):
  • 对于 'response' 钩子:def hook_func(response, **kwargs):
  • 对于 'error' 钩子:def hook_func(exc, **kwargs):
 
重要提示:
 
  • 钩子函数应该返回与输入相同类型的对象,或者 None。例如,response 钩子应该返回一个 Response 对象,否则后续的处理(包括你自己的代码)可能会出错。如果你只想 “观察” 而不 “修改”,只需返回接收到的对象即可。
  • **kwargs 参数是必须的,因为 requests 可能会在未来版本中传递更多参数。

2.3 使用示例

让我们通过几个例子来具体看看如何使用。
示例 1:简单的日志记录(response 钩子)
这是最常见的用法之一,用于打印出请求和响应的详细信息。
 
import requests

def print_response_details(response, **kwargs):
    """打印响应的详细信息"""
    print(f"请求 URL: {response.url}")
    print(f"状态码: {response.status_code}")
    print(f"响应头: {response.headers}")
    print(f"响应内容: {response.text[:100]}...")  # 只打印前100个字符
    print("-" * 50)
    return response  # 必须返回 response 对象

url = 'https://api.github.com/users/octocat'

# 在 get 请求中添加 hooks
response = requests.get(url, hooks={'response': print_response_details})

# 你的后续代码...
# print(response.json())

 

示例 2:请求前修改 headers(request 钩子)
假设你想为所有请求自动添加一个 User-Agent 头。
import requests

def add_custom_header(request, **kwargs):
    """在请求发送前添加自定义的 User-Agent"""
    request.headers['User-Agent'] = 'MyCustomUserAgent/1.0'
    print(f"修改后的请求头: {request.headers}")
    return request # 必须返回 request 对象

url = 'https://httpbin.org/headers' # 这个网站会返回你的请求头

# 发送请求
response = requests.get(url, hooks={'request': add_custom_header})

print(response.text)
 

 

 
运行后,你会在 response.text 中看到 User-Agent 已经被修改为我们自定义的值。
示例 3:处理错误并自动重试(response 钩子)
这个例子展示了如何在遇到 500 Internal Server Error 时自动重试请求。
 
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

# 方法一:使用 urllib3 的 Retry 机制(更推荐)
# 这是处理重试的标准方法,功能更强大
def create_retry_session():
    session = requests.Session()
    retry_strategy = Retry(
        total=3,  # 总重试次数
        backoff_factor=1, # 重试间隔时间(1, 2, 4, ...秒)
        status_forcelist=[429, 500, 502, 503, 504], # 对这些状态码重试
        allowed_methods={"GET", "POST"} # 对这些方法重试
    )
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("https://", adapter)
    session.mount("http://", adapter)
    return session

# 使用带有重试机制的 Session
# session = create_retry_session()
# response = session.get("https://httpbin.org/status/500")
# print(response.status_code)

# 方法二:使用 hooks 实现一个简单的重试(仅作演示)
# 注意:这种方法不如 Retry 机制健壮,例如它不处理 backoff 等
def simple_retry_hook(response, **kwargs):
    if response.status_code == 500:
        print(f"服务器内部错误 (500),正在重试...")
        # 可以在这里再次调用 requests.get/post,但要注意避免无限循环
        # 这是一个简化的例子,实际应用中需要更完善的逻辑
        # 通常,我们会结合 session 和 hooks 来实现
        return requests.get(response.url, hooks={'response': simple_retry_hook})
    return response

# 演示如何使用
try:
    # 使用一个会随机返回 500 的测试地址
    response = requests.get("https://httpbin.org/status/500", hooks={'response': simple_retry_hook})
    print(f"最终状态码: {response.status_code}")
except requests.exceptions.RetryError as e:
    print(f"重试多次后仍然失败: {e}")
 

 

 
注意:对于重试逻辑,官方更推荐使用 urllib3 的 Retry 机制配合 requests.Session,如上面代码注释中所示。hooks 提供了另一种灵活的实现方式,但通常更适合简单的场景。

3. 在 Session 中使用 hooks

如果你在一个会话(Session)中发送多个请求,并且希望所有请求都应用相同的钩子,你可以在创建 Session 时设置 hooks
 
import requests

def log_request(request, **kwargs):
    print(f"发送请求到: {request.url}")
    return request

def log_response(response, **kwargs):
    print(f"收到响应,状态码: {response.status_code}")
    return response

# 创建一个带有钩子的 Session
s = requests.Session()
s.hooks.update({
    'request': log_request,
    'response': log_response
})

# 使用这个 Session 发送的所有请求都会触发钩子
s.get('https://api.github.com/users/octocat')
print("---")
s.get('https://api.github.com/repos/psf/requests')
 

总结

hooks 是 requests 库中一个非常灵活和强大的功能。它允许你在不侵入主逻辑的情况下,对请求的整个生命周期进行精细的控制和扩展。
  • 核心思想:在请求的特定阶段插入自定义函数。
  • 常用事件:'request' (前), 'response' (后), 'error' (错误时)。
  • 使用方式:作为参数传递给 requests.get/post 等方法,或在 Session 对象上设置。
  • 注意事项:钩子函数通常需要返回它们接收的对象(request 或 response),以便请求链能够继续。
posted @ 2025-11-24 11:53  非文艺女青年  阅读(5)  评论(0)    收藏  举报
levels of contents