You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Java调用GitHub API下载Release资产返回空文件

解决GitHub私有仓库Release资产下载后文件为空的问题

你的代码有两个关键问题导致下载的文件为空:


1. HttpClient重定向配置完全无效

你在static块里调用的httpClient.followRedirects()只是获取当前的重定向策略,根本不是设置方法。Java 11的HttpClient默认重定向策略是NORMAL,但如果要明确开启重定向,正确的创建方式应该是:

static final HttpClient httpClient = HttpClient.newBuilder()
        .followRedirects(HttpClient.Redirect.NORMAL)
        .build();

之前的写法等于没做任何配置,当GitHub API返回302重定向时,你的代码直接把302当成成功,但302响应本身没有文件内容,只有跳转地址,所以写入的文件自然是空的。

2. 重定向时携带Authorization头导致请求失败

GitHub的Release资产API返回的302跳转目标是raw.githubusercontent.com的临时签名URL,这个URL本身已经包含认证信息,不需要再携带原来的Bearer Token。如果HttpClient自动把Authorization头带到跳转后的请求里,会触发GitHub权限校验失败,返回403,最终导致下载的文件为空。

要解决这个问题,需要给HttpClient添加重定向处理器,跳转时移除Authorization头:

static final HttpClient httpClient = HttpClient.newBuilder()
        .followRedirects(HttpClient.Redirect.NORMAL)
        .redirectHandler(new RedirectHandler() {
            @Override
            public Optional<HttpRequest> handle(HttpRequest request, HttpResponse response, HttpClient.Redirect redirect) throws IOException {
                var newRequest = RedirectHandler.Default.handle(request, response, redirect);
                return newRequest.map(req -> {
                    // 重定向到不同域名时,移除Authorization头
                    if (!req.uri().getHost().equals(request.uri().getHost())) {
                        return HttpRequest.newBuilder(req)
                                .removeHeader("Authorization")
                                .build();
                    }
                    return req;
                });
            }
        })
        .build();

3. 修正响应状态码的判断逻辑

当HttpClient自动跟随重定向后,最终的响应码应该是200(成功下载文件),302只是中间跳转状态,不应该直接判定为成功。所以判断逻辑要改成只检查200:

if (response.statusCode() == 200) {
    System.out.println("Downloaded " + uri);
    return true;
}

修正后的完整代码

static final HttpClient httpClient = HttpClient.newBuilder()
        .followRedirects(HttpClient.Redirect.NORMAL)
        .redirectHandler(new RedirectHandler() {
            @Override
            public Optional<HttpRequest> handle(HttpRequest request, HttpResponse response, HttpClient.Redirect redirect) throws IOException {
                var newRequest = RedirectHandler.Default.handle(request, response, redirect);
                return newRequest.map(req -> {
                    if (!req.uri().getHost().equals(request.uri().getHost())) {
                        return HttpRequest.newBuilder(req)
                                .removeHeader("Authorization")
                                .build();
                    }
                    return req;
                });
            }
        })
        .build();

static boolean downloadAsset(URI uri, Path targetPath, String bearerToken) {
    try {
        var request = HttpRequest.newBuilder(uri)
                .header("Authorization", "Bearer " + bearerToken)
                .header("Accept", "application/octet-stream")
                .build();
        var response = httpClient.send(request, HttpResponse.BodyHandlers.ofFile(targetPath));
        if (response.statusCode() == 200) {
            System.out.println("Downloaded " + uri);
            return true;
        }
        Files.deleteIfExists(targetPath);
        System.err.println("Download failed with status code: " + response.statusCode());
    } catch (Exception e) {
        e.printStackTrace();
        try {
            Files.deleteIfExists(targetPath);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
    return false;
}

内容的提问来源于stack exchange,提问作者A. M.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 12:26:35