Python Requests无法识别高延迟请求的服务器响应应如何处理?
问题根因
你当前的服务在45分钟的运行周期内没有任何数据返回,全链路的中间节点(包括客户端所在网络的NAT网关、运营商路由、Cloud Run前置代理等)都会因为TCP连接长时间无数据传输,主动断开空闲连接,就算服务端最终生成了响应,客户端也已经收不到了,requests表现为无限挂起或者超时。
解决方案
一、优先修改服务端逻辑,保持连接活跃
这个是最稳妥的方案,避免中间节点断连。把原来的一次性返回改成流式响应,定期发送少量数据维持连接存活,示例代码:
from flask import Flask, Response import time import os import json app = Flask(__name__) @app.route("/") def test_high_latency_request(): def generate(): i=0 while i < 9: time.sleep(300) i+=1 print(str(i*5) + " mins have passed") # 每5分钟发送一个空白字符,维持连接 yield " " # 最后返回实际的JSON数据 yield json.dumps({"asgfd":"dagdfs","fgasdg":"gsadgs"}) return Response(generate(), mimetype="application/json") if __name__=="__main__": app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
客户端拿到流式响应后,最后把所有返回的内容拼起来去掉空白字符就是实际的JSON。
二、客户端开启TCP保活配置
requests默认没有开启TCP保活,需要手动配置Session的HTTPAdapter开启,避免客户端主动断连,示例代码:
import requests from requests.adapters import HTTPAdapter import socket from urllib3.connection import HTTPConnection # 配置TCP保活参数 HTTPConnection.default_socket_options = HTTPConnection.default_socket_options + [ (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), # 空闲30秒后开始发送保活包 (socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 30), # 每10秒发一次保活包 (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 10), # 连续5次保活失败就断开连接 (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5) ] session = requests.Session() # 超时设置为2800秒,比45分钟多留100秒余量 resp = session.get("https://high-latency-conn-test-hyk3kw2bxq-nw.a.run.app", timeout=2800) print(resp.json())
三、可选替换其他HTTP库
如果requests的配置无法满足需求,可以换用对长连接支持更灵活的库:
httpx:配置TCP保活更简单,支持同步和异步模式,长期维护更新,对高延迟场景适配更好aiohttp:异步HTTP库,适合同时发起多个长延迟请求的场景,资源占用更低
注意事项
- 提前确认Cloud Run的请求超时配置已经调整到大于45分钟,Cloud Run默认请求超时为5分钟,需要手动修改,最大可设置为60分钟
- 如果客户端运行在企业内网,还要确认内网网关的空闲连接超时阈值,发送心跳包的间隔要小于该阈值
内容的提问来源于stack exchange,提问作者steak_ale_piethon
相关产品推荐
相关产品推荐

