PAYATHON 2026

支付宝账单下载出现 UnknownHostException 如何解决?

支付小周

结论

java.net.UnknownHostException: dwbillcenter-2-1-1.daily.alipay.net 表明服务器无法通过 DNS 解析下载地址中的主机名。异常发生在 HTTP 连接建立之前,通常与下载地址是否超过 30 秒无关。

域名中的 daily.alipay.net 很可能属于支付宝的测试、沙箱或内部环境,公网服务器通常无法直接解析或访问。排查时应先确认账单下载地址的来源、支付宝网关配置,以及应用环境是否混用,而不是延长超时时间。

为什么不是下载超时

下载地址的有效期与网络请求超时不是一回事:

  • 地址有效期决定支付宝是否接受下载请求。
  • UnknownHostException 表示 DNS 解析失败,此时客户端还没有连接到支付宝服务器。
  • 如果地址已经失效,通常会收到 HTTP 响应或业务错误,而不是 UnknownHostException。
  • 调大 connectTimeout 或 readTimeout 无法解决域名解析失败。

异常中最需要关注的是:

java.net.UnknownHostException: dwbillcenter-2-1-1.daily.alipay.net

需要查清 dwbillcenter-2-1-1.daily.alipay.net 为什么会出现在接口返回结果中,同时确认程序的运行环境能否解析这个域名。

排查步骤

1. 检查支付宝网关配置

先确认获取账单下载地址时使用的是生产网关还是沙箱网关。

生产环境通常配置为:

https://openapi.alipay.com/gateway.do

沙箱环境通常使用:

https://openapi.alipaydev.com/gateway.do

如果应用、公钥、私钥和网关分属不同环境,接口可能返回异常地址,行为也可能与预期不符。以下配置应属于同一套环境:

  • appId
  • 支付宝网关地址
  • 应用私钥
  • 支付宝公钥或支付宝公钥证书
  • 应用公钥证书
  • 支付宝根证书
  • 账单所属账号

不要只改网关地址,也不要把沙箱密钥用于生产环境。

2. 记录接口返回的原始下载地址

获取账单地址后,在做好脱敏的前提下记录以下信息:

  • 调用的支付宝网关
  • appId
  • bill_type
  • bill_date
  • 接口响应码和子响应码
  • 返回下载地址的 host
  • 请求和响应时间

Java 中可以单独提取 host:

import java.net.URI;

String downloadUrl = billDownloadUrl;
URI uri = URI.create(downloadUrl);

System.out.println("scheme = " + uri.getScheme());
System.out.println("host = " + uri.getHost());

如果接口直接返回 *.daily.alipay.net,说明这个地址不是下载代码拼接出来的。此时应继续核对调用环境,必要时把请求日志和支付宝接口响应提交给支付宝技术支持确认。

3. 检查是否自行拼接或改写了下载地址

账单接口返回的下载地址一般应当作为完整 URL 直接使用,不要进行以下处理:

  • 自行替换域名
  • 手工拼接 path 和查询参数
  • 对整个 URL 重复进行 URL 编码
  • 删除或重新排序查询参数
  • 通过配置文件覆盖返回地址的 host
  • 将生产地址转换成测试地址

下载 URL 往往带有临时授权参数。直接把 daily.alipay.net 换成其他域名并不可靠,还可能导致签名或授权校验失败。

4. 在实际运行服务器上检查 DNS

DNS 检查应在发生异常的服务器或容器中执行,不能只在开发电脑上测试:

nslookup dwbillcenter-2-1-1.daily.alipay.net

也可以使用:

dig dwbillcenter-2-1-1.daily.alipay.net

如果查询不到 IP 地址,结果就与 UnknownHostException 相符。还需要检查:

  • /etc/resolv.conf 中的 DNS 配置
  • 容器或 Kubernetes Pod 的 DNS 配置
  • CoreDNS 是否正常
  • 企业网络是否拦截外部 DNS
  • HTTP 代理是否配置正确
  • JVM 是否缓存了旧的 DNS 结果

对于 daily.alipay.net 这类疑似非公网环境的域名,不建议修改 hosts 文件并强行绑定 IP。IP 可能发生变化,即使建立了连接,后续仍可能因为 TLS 证书、路由或访问权限而失败。

5. 确认沙箱是否支持所需账单场景

如果当前使用沙箱网关,需要确认沙箱是否支持对应的账单下载能力和账单数据。不同接口和业务场景的沙箱支持范围可能不同,接口返回成功并不代表下载地址一定能从公网访问。

如果沙箱返回了 daily.alipay.net 地址,而业务最终需要下载真实账单,通常应改用配置完整的生产应用进行验证。是否属于支付宝侧的环境问题,应以当前接口文档和支付宝技术支持的确认结果为准。

推荐的下载实现

下载地址有时效性,获取成功后应立即使用,并为连接和读取设置合理的超时时间。下面使用 JDK 11 的 HttpClient:

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
import java.time.Duration;

public class AlipayBillDownloader {

    public static void download(String downloadUrl, Path target)
            throws IOException, InterruptedException {

        URI uri = URI.create(downloadUrl);

        if (!"https".equalsIgnoreCase(uri.getScheme())) {
            throw new IllegalArgumentException("Unexpected URL scheme");
        }

        if (uri.getHost() == null || uri.getHost().isBlank()) {
            throw new IllegalArgumentException("Invalid download URL");
        }

        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .followRedirects(HttpClient.Redirect.NORMAL)
                .build();

        HttpRequest request = HttpRequest.newBuilder(uri)
                .timeout(Duration.ofSeconds(30))
                .GET()
                .build();

        HttpResponse<Path> response = client.send(
                request,
                HttpResponse.BodyHandlers.ofFile(target)
        );

        if (response.statusCode() < 200 || response.statusCode() >= 300) {
            throw new IOException(
                    "Download failed, HTTP status = " + response.statusCode()
            );
        }
    }
}

调用时使用账单接口刚刚返回的完整 URL:

String downloadUrl = response.getBillDownloadUrl();
AlipayBillDownloader.download(
        downloadUrl,
        Path.of("/data/alipay-bill.zip")
);

实际文件可能是压缩包、文本或其他账单格式,不能仅凭业务描述中的“Excel”判断文件类型。具体处理方式应结合响应头、接口文档和实际文件内容确定。

针对 UnknownHostException 的异常处理

可以单独捕获 DNS 解析异常,将它与地址失效或 HTTP 错误区分开:

import java.net.UnknownHostException;

try {
    AlipayBillDownloader.download(downloadUrl, target);
} catch (UnknownHostException e) {
    throw new IllegalStateException(
            "账单下载域名无法解析,请检查支付宝环境配置和服务器 DNS。host="
                    + URI.create(downloadUrl).getHost(),
            e
    );
}

捕获到该异常后,不要针对同一个异常域名进行高频重试。DNS 无法解析时,短时间内反复请求通常没有意义。可以按以下顺序处理:

  1. 重新核对网关和应用环境。
  2. 必要时重新调用账单下载地址查询接口。
  3. 检查新地址的 host 是否仍为 daily.alipay.net。
  4. 如果持续返回同类地址,保留接口响应、请求时间和支付宝请求标识,并联系支付宝技术支持。

注意事项

  • 不要在日志中输出完整的临时下载 URL,其中可能含有敏感授权参数。
  • 下载地址获取后应立即使用,不要放入队列长时间等待。
  • 不要试图通过延长 HTTP 超时解决 UnknownHostException。
  • 不要自行替换支付宝返回 URL 中的域名。
  • 不要使用固定 IP 或 hosts 配置绕过 DNS。
  • 生产与沙箱的网关、应用和密钥必须配套使用。
  • 如果生产网关仍返回 daily.alipay.net,并且应用没有改写 URL,应将其视为异常响应,携带脱敏后的请求参数、响应内容和请求标识向支付宝核实。

备注:内容仅供参考。