惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Latest
Security Latest
G
Google Developers Blog
量子位
WordPress大学
WordPress大学
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
阮一峰的网络日志
阮一峰的网络日志
S
SegmentFault 最新的问题
Blog — PlanetScale
Blog — PlanetScale
B
Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Proofpoint News Feed
美团技术团队
V
Visual Studio Blog
Last Week in AI
Last Week in AI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
F
Fortinet All Blogs
博客园 - Franky
The Register - Security
The Register - Security
O
OpenAI News
Google DeepMind News
Google DeepMind News
A
Arctic Wolf
罗磊的独立博客
博客园 - 叶小钗
博客园 - 聂微东
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Y
Y Combinator Blog
SecWiki News
SecWiki News
T
Tor Project blog
月光博客
月光博客
S
Secure Thoughts
博客园 - 【当耐特】
Help Net Security
Help Net Security
D
Docker
Recent Announcements
Recent Announcements
GbyAI
GbyAI
B
Blog RSS Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
The Blog of Author Tim Ferriss
Webroot Blog
Webroot Blog
V
Vulnerabilities – Threatpost
Forbes - Security
Forbes - Security
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Hacker News: Ask HN
Hacker News: Ask HN
Cyberwarzone
Cyberwarzone
宝玉的分享
宝玉的分享
Cisco Talos Blog
Cisco Talos Blog
I
InfoQ
Microsoft Security Blog
Microsoft Security Blog

方永、南天紫雲

linux透明代理 技术的边界 停机问题通俗说明 Rust与oracle、redis集群的纠结 学习能力的增长 微信调试的原语 mac外接移动硬盘安装ArchLinux linux的死机问题 linux下全键盘操作 漂亮又好用的bspwm linux本机透明代理 ssh、mosh、autossh linux不能待机又一例 从WordPress切换到Hugo 折腾电脑开机 linux系统QQ新思路 Arch Linux的字体渲染 svn管理之submin OpenWrt自动fucking墙記錄 二维码(qrcode)名片的一些事儿 用lua nginx module搭建一个二维码(qr code)生成器 CentOS 7 安裝註記 php程序連接MySQL时只能127.0.0.1而localhost無法連接的問題 ThinkPad之FAN_ERROR、hi fi聲卡 jetty多端口部署 OpenWrt簡單暴力限網 linux中cron之PATH变量 OpenWrt的WDS無線橋接模式 再敘OpenWrt下的rtl8187無線中繼 sed之模擬tail 終端進化之二零一三 linux下的郵件服務器:postfix_dovecot_roundcube 一次性密碼/動態口令卡原理 xl2tp之VPN靜態地址分配 rtl2838U2832试用记 linux中pptp协议VPN搭建 glances监控工具安装 CentOS6.4硬盘安装 Debian Wheezy硬盤/U盤安裝小記 Kirby小試 zsh shell怎么打开常用的目录? OpenWrt SSH免密码使用密钥登录 linux中的vsftpd的匿名(anonymous)用户配置 無光驅無USB無軟驅,怎麼修復硬盤MBR? 那些個人網站 linuxFreeBSD下的dnspod动态域名客户端 Windows系统盘的32K之殇 一枚Chrome插件引起的大量磁盤IO問題 用批處理切換網卡的IP(適用Win7、Win8) Windows中的DHCP服务器 Win8啓動時出現“您的電腦需要修復”問題的解決辦法 Windows8睡眠(待机)模式异常处理 最强大好用而又小巧的计算器 Windows8運行不能保存歷史命令 Win8下的红警2尤里复仇 为cmd添加readline,如Bash Shell般使用cmd 手动添加修改win8 win+x菜单 Win8運行卸載程序時提示2503之解決一法 烽火HG110提权一法 缓解眼疲劳有效的办法 mintty乱码解决办法 糟糠美妾 免费易用的Win8 ArchLinux的類box環境音量調節二三事 使用OpenWrt与curl挂QQ OpenWrt的安全 OpenWrt BCM63xx rtl8187使用注意事项 Arch Linux之systmed使用简介 Archlinux 2012.07.15之后发布的镜像新手安装完全向导 FreeBSD 9.0 安装简记 记一由FreeBSD引发的午夜惊魂 Jekyll or handmade wi-fi无线破解过程与原理简要介绍 修复QQ影音异常卸载后的文件关联 吐槽一下000webhost 为OpenWrt的luci Web界面加速 最小的sed for Windows linux的磁盘自动挂载 OpenWrt中crontab -e的使用 sddns(dnspod client for OpenWrt)使用说明 OpenWrt中vsftp添加新用户 php+markdown写博客 linux arp防火墙之p2p终结者 墙外的世界很精彩 OpenWrt使用dnspod的动态域名解析(ddns)功能 OpenWrt架设nginx php网站 openwrt架设uhttpd+php+sqlite网站 vim自动跳到上次离开的光标位置 OpenWrt无线中继配置文件 修行八支 漫步者R201T打摩升级改造 阿里(Ali)3328系dvb接收机软件升级方法 db120刷OpenWrt固件并使用ppp方式ADSL拨号 移动短信助手 chrome tips一则 cdate,显示中国传统农历日期 更改硬盘模式为AHCI后Windows及linux的调整 使用grub2加载软盘和光盘镜像 电脑用数据线连接手机上网 电脑通过蓝牙连接手机GPRS上网
reqwest请求报错的调试记录
zola · 2026-04-15 · via 方永、南天紫雲

一个 rust 程序使用了 reqwest ,频繁地报错 error sending request for url ,调试过程记录一下。

reqwestError 使用 thiserror 接收

  #[error(transparent)]
  Reqwest(#[from] reqwest::Error),

在外层程序打印报错信息:

let source = e.source();
tracing::error!("{e}, source: {source:?}");

source 是:

source: Some(hyper_util::client::legacy::Error(Connect, ConnectError("dns error", Custom { kind: Uncategorized, error: "failed to lookup address information: Name has no usable address" })))

确定是 dns 查询问题,怀疑是优先查询了 ipv6 ,因为要查询的域名是禁用了 ipv6 地址解析的。reqwest 换用 hickory-dns ,得到报错信息:

source: Some(hyper_util::client::legacy::Error(Connect, ConnectError("dns error", ResolveError { kind: Proto(ProtoError { kind: NoRecordsFound { query: Query { name: Name("example.com."), query_type: AAAA, query_class: IN }, soa: Some(Record { name_labels: Name("example.com."), dns_class: IN, ttl: 10, rdata: SOA { mname: Name("ns.co.uk."), rname: Name("example.com."), serial: 1, refresh: 7200, retry: 900, expire: 1209600, minimum: 60 } }), ns: None, negative_ttl: Some(9), response_code: NoError, trusted: true, authorities: None } }) })))

于是确定了是查询 ipv6 导致的。

reqwest 是否提供配置项,找到代码:

reqwest hickory

/// Create a new resolver with the default configuration,
/// which reads from `/etc/resolve.conf`. If reading `/etc/resolv.conf` fails,
/// it fallbacks to hickory_resolver's default config.
/// The options are overridden to look up for both IPv4 and IPv6 addresses
/// to work with "happy eyeballs" algorithm.
fn new_resolver() -> TokioResolver {
    let mut builder = TokioResolver::builder_tokio().unwrap_or_else(|err| {
        log::debug!(
            "hickory-dns: failed to load system DNS configuration; falling back to hickory_resolver defaults: {:?}",
            err
        );
        TokioResolver::builder_with_config(
            ResolverConfig::default(),
            TokioConnectionProvider::default(),
        )
    });
    builder.options_mut().ip_strategy = LookupIpStrategy::Ipv4AndIpv6;
    builder.build()
}

果然是双栈查询,但是这个查询策略在 reqwest 中是无法修改的,那 hickory-dns 会不会读取系统的配置,从而改变这种行为呢?

修改 /etc/gai.conf,将 precedence ::ffff:0:0/96 100 这行的注释打开,还是在报错,可能是换成了 hickory-dns ,它并不读取这个配置文件。

再根据 gemini 的说法修改 /etc/resolv.conf ,加一行 options no-aaaa 。唉,可以了,不再报错了。

hickory-dns ,它用了 hickory-dns/resolv-conf 这个 crate,它里面定义的选项很多,其中有两个和 ipv6 解析有关: inet6, no-aaaa

inet6 只是一个启用开关,并没有提供 no-inet6 这种禁用的选项,那用且只能用 no-aaaa 选项了。

改完用了一段时间,发现报错又出现了。 reqwest 的 Client builder 提供了 dns_resolver 方法,可以自定义 dns 的解析。 将 reqwest hickory 这段代码复制过来,然后将查询策略设置为 LookupIpStrategy::Ipv4Only ,再次运行,这次的错误变成了:

Some(hyper_util::client::legacy::Error(Connect, ConnectError("dns error", ResolveError { kind: Proto(ProtoError { kind: NoRecordsFound { query: Query { name: Name("example.com."), query_type: A, query_class: IN }, soa: None, ns: None, negative_ttl: None, response_code: NoError, trusted: true, authorities: None } }) })))

通过这个报错,回顾一下查询策略,它提供这几种方式:

pub enum LookupIpStrategy {
    Ipv4Only,
    Ipv6Only,
    Ipv4AndIpv6,
    Ipv6thenIpv4,
    Ipv4thenIpv6,
}

hickory-dns 的默认值是 Ipv4thenIpv6 , reqwest 的值是 Ipv4AndIpv6

也就是说,查询策略不是根本原因,ipv4 查询失败才是根本所在。通过观察,最近到上游 dns server 的网络不稳定,某段时间丢包率较高,从而导致 ipv4 查询失败的呢?

又进行了测试和对比,发现即使在国外VPS上用 drill 执行查询,仍然偶尔出现 The answer packet was truncated 的警告,将上游从 1.1.1.1 换成 8.8.8.8,运行一段时间,报错不再出现。

再挖这个警告,gemini给出的回复是

传统的 DNS 协议基于 UDP,且标准规定响应报文不能超过 512 字节,当服务器发现包太长发不出去时,会设置 DNS 报文头部的 TC (Truncated) 标志位。客户端收到带 TC 标志的包后,就会提示“报文被截断”。 为了解决 512 字节限制,引入了 EDNS(0) 扩展,允许 UDP 包最大达到 4096 字节。