必须显式设置timeout=(连接超时,读取超时),如(3,10),并配合Retry策略重试,捕获requests.exceptions.Timeout异常;避免无限等待导致主线程卡死。

Flask里用requests发请求时,超时没设会卡死主线程
Flask默认是同步阻塞模型,如果调用第三方API时不显式设置timeout,一旦对方响应慢或网络抖动,requests.get()可能无限等待,导致整个Web请求挂起,用户看到白屏或504,服务端CPU不高但连接数暴涨。
必须为每个requests调用指定timeout参数,且建议拆分为连接超时和读取超时:
-
timeout=(3, 10):3秒连不上就放弃,连上后最多等10秒响应体传完 - 避免只写
timeout=10——它等价于(10, 10),连接阶段耗太久也会拖住请求 - 超时异常是
requests.exceptions.Timeout,不是Exception的通用捕获能覆盖全
重试不能靠while True裸循环,要用urllib3.util.retry.Retry
手动写重试逻辑容易出错:忘记退避、重试次数失控、没区分可重试错误类型。直接复用requests底层的Retry机制更稳。
关键配置点:
立即学习“Python免费学习笔记(深入)”;
- 用
status_forcelist=[429, 500, 502, 503, 504]明确哪些HTTP状态码值得重试,别把400、401也包进去 -
backoff_factor=0.3会让第2次重试延迟0.3秒,第3次延迟0.6秒,第4次延迟1.2秒(指数退避) - 必须把
Retry对象挂到requests.Session()上,而不是每次新建requests.get()
示例片段:
火焰围攻 授权: q15040409-creator.功能概述火焰围攻 授权: q15040409-creator.是一项面向实际任务的技能,主要用于Description.;Flask Web. - Python.;核心要点HTTP?;.Version.1.0.tags. wrap.github.automation.。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。使用与执行使用时应结合输入条件选择合适的执行方式,核对必要参数、依赖环境与输出内容,并按原始要
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retry_strategy = Retry(
total=3,
status_forcelist=[429, 500, 502, 503, 504],
backoff_factor=0.3
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)
session.mount("http://", adapter)
Flask视图函数里混用同步requests和异步逻辑会出问题
有人想“加个async装饰器让重试不卡”,但Flask 2.x默认不支持原生async视图(除非用flask 2.3+ + enable_async=True,且所有中间件兼容)。强行套await会导致RuntimeWarning: coroutine 'xxx' was never awaited或500错误。
务实做法是保持同步,但做到三点:
- 超时值设得比Nginx/反向代理的
proxy_read_timeout小至少2秒(比如Nginx设30秒,这里用(3, 25)) - 重试总耗时上限要可控——
total=3+backoff_factor=0.3≈ 最多耗时3 + 0.3 + 0.6 + 1.2 ≈ 5秒 - 对非核心链路(如埋点上报、日志推送),直接设成
timeout=(1, 2)+total=1,失败就丢弃,别拖慢主流程
错误日志里不打完整response.text,防止敏感信息泄露
第三方API返回的错误体里可能含用户ID、token片段、内部路径等。直接logger.error(f"API failed: {resp.text}")等于把凭证打到日志文件里。
正确做法:
- 只记录
resp.status_code、resp.request.url、resp.headers.get("X-Request-ID")(如果有) - 用
repr(resp.content[:200])代替resp.text,避免编码问题,且截断长度 - 把重试次数、最终是否成功作为结构化字段打到日志,方便后续查重试效果
真正需要调试时,再临时开启logging.getLogger("urllib3").setLevel(logging.DEBUG)看原始请求头和响应头。

















