方永、南天紫雲

道亦有道

reqwest请求报错的调试记录
2026年04月15日

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

reqwest 的 Error 使用 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 选项了。