为何Python的requests.get请求调用出现挂起问题?
问题描述
本地运行Python requests脚本发起GET请求无响应,但curl和同一硬件的WSL环境下运行脚本正常:
复现脚本
基础版本:
import requests print(requests.get('https://api.openstreetmap.org/api/0.6/node/1894790125'))
指定通用User-Agent后问题仍存在:
import requests print(requests.get( 'https://api.openstreetmap.org/api/0.6/node/1894790125', headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' } ))
tcpdump抓包信息
执行抓包命令:
sudo tcpdump -v -i eno1 'host api.openstreetmap.org'
抓包输出:
tcpdump: listening on eno1, link-type EN10MB (Ethernet), snapshot length 262144 bytes 08:17:22.463843 IP6 (flowlabel 0x69a8c, hlim 64, next-header TCP (6) payload length: 40) aaaa:bbbb:cccc:dddd:eeee:dddd:cccc:bbbb.aaaa4 > spike-06.openstreetmap.org.https: Flags [S], cksum 0xdb71 (incorrect -> 0xb5a5), seq 3910911789, win 64800, options [mss 1440,sackOK,TS val 1030348905 ecr 0,nop,wscale 7], length 0 08:17:23.482673 IP6 (flowlabel 0xd077e, hlim 64, next-header TCP (6) payload length: 40) aaaa:bbbb:cccc:dddd:eeee:dddd:cccc:bbbb.aaaa4 > spike-06.openstreetmap.org.https: Flags [S], cksum 0xdb71 (incorrect -> 0xb1aa), seq 3910911789, win 64800, options [mss 1440,sackOK,TS val 1030349924 ecr 0,nop,wscale 7], length 0 08:17:25.494643 IP6 (flowlabel 0x3cc5c, hlim 64, next-header TCP (6) payload length: 40) aaaa:bbbb:cccc:dddd:eeee:dddd:cccc:bbbb.aaaa4 > spike-06.openstreetmap.org.https: Flags [S], cksum 0xdb71 (incorrect -> 0xa9ce), seq 3910911789, win 64800, options [mss 1440,sackOK,TS val 1030351936 ecr 0,nop,wscale 7], length 0 08:17:29.687440 IP6 (flowlabel 0x7665b, hlim 64, next-header TCP (6) payload length: 40) aaaa:bbbb:cccc:dddd:eeee:dddd:cccc:bbbb.aaaa4 > spike-06.openstreetmap.org.https: Flags [S], cksum 0xdb71 (incorrect -> 0x996e), seq 3910911789, win 64800, options [mss 1440,sackOK,TS val 1030356128 ecr 0,nop,wscale 7], length 0 08:17:37.878687 IP6 (flowlabel 0xd5551, hlim 64, next-header TCP (6) payload length: 40) aaaa:bbbb:cccc:dddd:eeee:dddd:cccc:bbbb.aaaa4 > spike-06.openstreetmap.org.https: Flags [S], cksum 0xdb71 (incorrect -> 0x796e), seq 3910911789, win 64800, options [mss 1440,sackOK,TS val 1030364320 ecr 0,nop,wscale 7], length 0 08:17:54.010694 IP6 (flowlabel 0xbf2f2, hlim 64, next-header TCP (6) payload length: 40) aaaa:bbbb:cccc:dddd:eeee:dddd:cccc:bbbb.aaaa4 > spike-06.openstreetmap.org.https: Flags [S], cksum 0xdb71 (incorrect -> 0x3a6a), seq 3910911789, win 64800, options [mss 1440,sackOK,TS val 1030380452 ecr 0,nop,wscale 7], length 0 ^C 6 packets captured 28 packets received by filter 3 packets dropped by kernel
关键现象
- 本地Python脚本持续无响应,curl访问同一URL可立即获得结果
- WSL环境下运行相同脚本,正常返回
<Response [200]> - 抓包显示仅发送TCP SYN包,无服务器的SYN-ACK回应,且所有IPv6包的校验和被标记为
incorrect
原因分析与解决方案
核心原因:IPv6校验和异常导致连接失败
抓包中的cksum ... (incorrect -> ...)是关键线索:
- 校验和不匹配:系统发送的IPv6包校验和计算异常,要么是网络栈生成包时出错,要么是网卡的校验和卸载功能故障,导致服务器丢弃这些无效包,无法建立TCP连接。
- 协议优先差异:requests库默认优先使用IPv6连接目标地址,而curl可能自动 fallback 到IPv4;WSL环境的网络栈可能默认使用IPv4,或者其IPv6校验和功能正常,因此能正常建立连接。
解决方案
- 强制requests使用IPv4
修改脚本,强制通过IPv4发起请求:
import requests from requests.adapters import HTTPAdapter from urllib3.util.connection import create_connection def force_ipv4(host, port, **kwargs): return create_connection((host, port), source_address=None, timeout=kwargs.get('timeout'), family=4) session = requests.Session() adapter = HTTPAdapter() adapter.init_poolmanager(connection_factory=force_ipv4) session.mount('https://', adapter) print(session.get('https://api.openstreetmap.org/api/0.6/node/1894790125'))
- 关闭网卡IPv6校验和卸载
以Linux系统为例,执行命令关闭对应网卡的IPv6校验和卸载功能:
sudo ethtool -K eno1 tx-checksum-ipv6 off
测试有效后,可将该配置写入网卡永久配置文件,避免重启后失效。
- 临时禁用系统IPv6
若上述方法无效,可临时禁用系统IPv6,让requests自动切换到IPv4:
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1 sudo sysctl -w net.ipv6.conf.eno1.disable_ipv6=1
内容的提问来源于stack exchange,提问作者René Nyffenegger
相关产品推荐
相关产品推荐

