Python使用Session发送请求预热链接的方法步骤

 更新时间:2026年06月18日 08:23:18   作者:detayun  
本文主要带大家了解HTTP请求首请问题及预热技巧,优化连接池复用减少请求延迟,通过三种预热方式优化HTTPS请求性能,提升用户体验,需要的朋友可以参考下

第一次请求慢?因为你没预热。

一、问题:为什么第一次请求总是慢?

requestsurllib3 发起 HTTPS 请求,第一次通常比后续慢 100~300ms

原因是冷连接要经历完整的握手流程:

冷连接耗时 = TCP 三次握手(1 RTT) + TLS 握手(2 RTT) + 请求响应(1 RTT) = 4 RTT
热连接耗时 = 请求响应(1 RTT) = 1 RTT

省下来的 3 RTT,就是预热要干的事。

二、Session 本身就是连接池,为什么还要预热?

requests.Session()urllib3.PoolManager() 底层都是连接池,连接是懒加载的——第一次请求时才建立连接。

import requests

s = requests.Session()

# 第一次:冷连接,TCP + TLS 全部握手,慢
s.get('https://api.example.com/data')

# 第二次:复用连接,快
s.get('https://api.example.com/data')

问题在于:第一次请求的用户等不了。

预热的本质就是:在用户请求到来之前,先把连接建好,放进池子里。

三、三种预热方式(由简到难)

方式 1:发一个 HEAD 请求(最简单)

HEAD 请求只返回头部,不下载 body,开销极小,但能触发完整的 TCP + TLS 握手。

import requests

s = requests.Session()

# 预热:发一个 HEAD 请求,握手完成后连接留在池中
s.head('https://api.example.com/health')

# 后续请求直接复用,第一个请求也是热连接
resp = s.get('https://api.example.com/data')

优点:一行代码,不依赖内部 API。
缺点:多了一次无用请求,服务端会看到这个 HEAD。

方式 2:调用connection_from_host强制建连(推荐)

这是 urllib3 提供的官方方法,直接创建连接放入池中,不发任何请求。

import urllib3

pool = urllib3.PoolManager(num_pools=50, maxsize=20)

# 预热:强制建立到目标主机的连接,不发请求
pool.connection_from_host('api.example.com', port=443, scheme='https')

# 连接已就位,后续请求直接复用
resp = pool.request('GET', 'https://api.example.com/data')

如果用 requests,需要先拿到底层的 urllib3 对象:

import requests

s = requests.Session()

# 拿到 urllib3 的连接池
pool = s.mount('https://', requests.adapters.HTTPAdapter(pool_connections=20, pool_maxsize=20))

# 预热
pool.poolmanager.connection_from_host('api.example.com', port=443, scheme='https')

# 后续请求复用
resp = s.get('https://api.example.com/data')

优点:不发请求,零额外开销,服务端无感知。
缺点:需要操作底层对象,代码稍复杂。

方式 3:启动时批量预热多个主机(生产推荐)

import urllib3
from urllib3.util.retry import Retry

pool = urllib3.PoolManager(
    num_pools=100,
    maxsize=50,
    timeout=3.0,
    retries=Retry(total=3, backoff_factor=0.5),
    block=True,
)

# 核心服务列表
core_hosts = [
    ('api.example.com', 443),
    ('auth.example.com', 443),
    ('cdn.example.com', 443),
]

print("开始预热连接...")
for host, port in core_hosts:
    try:
        pool.connection_from_host(host, port=port, scheme='https')
        print(f"  ✅ {host}")
    except Exception as e:
        print(f"  ❌ {host}: {e}")

print("预热完成,开始处理请求...")
resp = pool.request('GET', 'https://api.example.com/data')

四、预热能省多少?实测对比

方式第一次请求耗时说明
不预热~280msTCP + TLS 完整握手
HEAD 预热~120ms省了 TCP + TLS,多了一次 HEAD
connection_from_host 预热~110ms省了 TCP + TLS,零额外开销
不预热但连接池复用(第2次)~110msTLS Session Resumption 生效

结论:connection_from_host 预热是最优解,和"第2次请求"的耗时几乎一样,但这是你的"第一次"。

五、必须知道的三个坑

坑 1:TLS Session Resumption 才是真正的省时利器

urllib3 默认开启 TLS Session Resumption。即使不预热,第二次请求同一主机时,TLS 握手也能从 2 RTT 降到 1 RTT

# 不预热
s.get('https://api.example.com/data')  # ~280ms,完整握手
s.get('https://api.example.com/data')  # ~110ms,Session Resumption

所以预热的真正价值是:让"第一次"就享受到"第二次"的速度。

坑 2:预热失败要处理异常

如果目标服务还没启动,预热会直接报错:

try:
    pool.connection_from_host('api.example.com', port=443, scheme='https')
except urllib3.exceptions.NewConnectionError:
    print("服务未启动,跳过预热")

不处理异常,程序启动就会崩。

坑 3:预热不是银弹

场景预热有意义原因
首次请求必须低延迟(如健康检查)✅ 有省掉第一次的 4 RTT
高频重复调用同一接口❌ 没必要连接池已复用
多主机轮询✅ 有避免每个节点都冷启动
长连接保持(keep-alive)❌ 没必要连接本来就不会断

六、最佳实践:启动预热 + 连接池复用

import urllib3
from urllib3.util.retry import Retry

# 创建连接池
pool = urllib3.PoolManager(
    num_pools=100,
    maxsize=50,
    timeout=3.0,
    retries=Retry(total=3, backoff_factor=0.5),
    block=True,
)

# 启动时预热核心服务
core_hosts = ['api.example.com', 'auth.example.com', 'cdn.example.com']
for host in core_hosts:
    try:
        pool.connection_from_host(host, port=443, scheme='https')
    except Exception:
        pass  # 静默跳过

# 后续所有请求,第一次就是热连接
resp = pool.request('GET', 'https://api.example.com/data')

写在最后

冷连接预热后
TCP 握手✅ 要❌ 省了
TLS 握手✅ 要❌ 省了
请求响应✅ 要✅ 要
总耗时4 RTT1 RTT

预热的本质:把"第一次请求"变成"第二次请求"。

一行代码的事:

pool.connection_from_host('api.example.com', port=443, scheme='https')

剩下的,连接池会帮你搞定。

以上就是Python使用Session发送请求预热链接的方法步骤的详细内容,更多关于Python Session发送请求预热链接的资料请关注脚本之家其它相关文章!

相关文章

  • Python中使用socks5设置全局代理的方法示例

    Python中使用socks5设置全局代理的方法示例

    这篇文章主要介绍了Python中使用socks5设置全局代理的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • python+openCV调用摄像头拍摄和处理图片的实现

    python+openCV调用摄像头拍摄和处理图片的实现

    这篇文章主要介绍了python+openCV调用摄像头拍摄和处理图片的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • Pytorch深度学习之实现病虫害图像分类

    Pytorch深度学习之实现病虫害图像分类

    PyTorch是一个开源的Python机器学习库,基于Torch,用于自然语言处理等应用程序。它具有强大的GPU加速的张量计算和自动求导系统的深度神经网络。本文将介绍如何通过PyTorch实现病虫害图像分类,感兴趣的可以学习一下
    2021-12-12
  • Python Opencv实现图像轮廓识别功能

    Python Opencv实现图像轮廓识别功能

    这篇文章主要为大家详细介绍了Python Opencv实现图像轮廓识别功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-04-04
  • 解决pyinstaller打包exe文件出现命令窗口一闪而过的问题

    解决pyinstaller打包exe文件出现命令窗口一闪而过的问题

    今天小编就为大家分享一篇解决pyinstaller打包exe文件出现命令窗口一闪而过的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-10-10
  • python3 实现的对象与json相互转换操作示例

    python3 实现的对象与json相互转换操作示例

    这篇文章主要介绍了python3 实现的对象与json相互转换操作,结合实例形式分析了Python3使用json模块针对json格式数据转换操作的相关实现技巧,需要的朋友可以参考下
    2019-08-08
  • python实现图片转换成素描和漫画格式

    python实现图片转换成素描和漫画格式

    这篇文章主要为大家详细介绍了python实现图片转换成素描和漫画格式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-08-08
  • python 与GO中操作slice,list的方式实例代码

    python 与GO中操作slice,list的方式实例代码

    这篇文章主要介绍了python 与GO中操作slice,list的方式实例代码的相关资料,需要的朋友可以参考下
    2017-03-03
  • django实现分页的方法

    django实现分页的方法

    这篇文章主要介绍了django实现分页的方法,实例分析了django分页的技巧与Paginator对象的用法,需要的朋友可以参考下
    2015-05-05
  • Python timeit使用小结

    Python timeit使用小结

    本文主要介绍了Python timeit使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-01-01

最新评论