沙箱环境下载交易账单报 UnknownHostException
结论
UnknownHostException 表示当前网络无法通过 DNS 解析域名 dwbillcenter-2-1-1.daily.alipay.net。
这个域名包含 daily.alipay.net,通常是支付宝日常或沙箱环境使用的内部域名,不是对公网开放的账单下载域名。关闭防火墙、切换浏览器或反复重试一般解决不了这个问题。错误也与 CSV 文件、URL 参数或浏览器兼容性无关。
原因分析
Java 访问下载地址前,会先将域名解析为 IP 地址。目标域名无法通过 DNS 解析时,就会抛出:
java.net.UnknownHostException: dwbillcenter-2-1-1.daily.alipay.net
可以使用下面的命令检查 DNS 解析结果:
nslookup dwbillcenter-2-1-1.daily.alipay.net
如果结果为 NXDOMAIN、Non-existent domain 或提示找不到主机,说明请求还没有连接到账单服务器,在域名解析阶段就已经失败。
这个地址还需要注意两点:
daily.alipay.net不是常规的公网生产域名;- URL 中含有
timestamp和token,通常是临时下载凭证。即使域名可以访问,链接也可能已经过期。
因此,修改浏览器设置、关闭防火墙或持续重试都不是合适的处理方式。
解决步骤
1. 不要直接使用该沙箱下载地址
不要把 daily.alipay.net 的地址写入业务代码,也不要将它作为生产环境的账单下载入口。即使该地址由沙箱接口返回,也不能说明公网客户端一定可以访问。
2. 确认沙箱是否支持账单文件下载
沙箱主要用于接口调用和交易流程联调,部分外围能力可能没有完整的公网下载链路。当前账单类型是否支持下载,应以支付宝开放平台最新的沙箱能力说明为准。
如果沙箱明确不支持账单文件下载,可以在本地准备一份结构与正式账单一致的测试文件,用来验证解压、解析、对账及异常处理逻辑。
3. 在正式环境中重新获取下载地址
进入生产联调后,应调用正式环境的账单下载接口获取新地址。以 alipay.data.dataservice.bill.downloadurl.query 为例,需要确认:
- 使用的是生产网关;
- 应用、商户账号和密钥均属于生产环境;
- 对应账单日期的账单已经生成;
- 获取地址后及时下载,不要长期保存临时 URL。
生产网关通常配置为:
https://openapi.alipay.com/gateway.do
沙箱网关通常配置为:
https://openapi.alipaydev.com/gateway.do
不要混用沙箱账号、生产网关、生产密钥或生产商户身份。
4. 沙箱持续返回内部域名时,提交平台排查
如果沙箱账单接口一直返回 daily.alipay.net 地址,应保存以下信息,并提交给支付宝开放平台技术支持排查:
- 调用的 API 名称;
- 请求时间;
app_id;- 账单日期和账单类型;
- 接口响应中的
code、sub_code、msg、sub_msg; - 返回的下载域名;
- 支付宝侧请求流水号或 trace 信息。
分享日志前,请删除或遮蔽 token、签名、私钥及其他敏感字段。
Java 处理示例
业务代码应分别处理“域名无法解析”和“HTTP 下载失败”,不要把 UnknownHostException 当作普通的可重试错误:
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.UnknownHostException;
public class BillDownloader {
public static void download(String downloadUrl) throws IOException {
URI uri = URI.create(downloadUrl);
if (uri.getHost() == null) {
throw new IllegalArgumentException("Invalid bill download URL");
}
if (uri.getHost().endsWith(".daily.alipay.net")) {
throw new IllegalStateException(
"The sandbox returned a non-public daily.alipay.net download URL"
);
}
HttpURLConnection connection =
(HttpURLConnection) uri.toURL().openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(10_000);
connection.setReadTimeout(30_000);
connection.setInstanceFollowRedirects(true);
try {
int status = connection.getResponseCode();
if (status != HttpURLConnection.HTTP_OK) {
throw new IOException("Bill download failed, HTTP status: " + status);
}
// 在此读取输入流并保存账单文件。
} catch (UnknownHostException e) {
throw new IOException(
"Cannot resolve bill download host: " + uri.getHost(), e
);
} finally {
connection.disconnect();
}
}
}
注意事项
- 不要在
hosts文件中随意为daily.alipay.net配置从网上找到的 IP。内部服务可能依赖专用网络、路由和鉴权,强行绑定 IP 通常没有效果,还可能造成安全风险。 - 不要在日志、工单或公开页面中泄露完整的下载 URL。示例地址中的
token属于敏感信息。如果链接仍然有效,建议重新获取。 UnknownHostException与 HTTP403、404、500的含义不同。前者表示客户端没有找到目标服务器,后者表示服务器已经收到请求。- 下载 URL 通常有有效期。生产环境获取地址后应立即下载,链接过期后需重新调用账单下载接口。
- 自动重试适合处理临时网络抖动。域名如果始终无法解析,继续重试没有意义,应停止重试并检查运行环境和接口返回的地址。
备注:内容仅供参考。
