Search code examples
javaziphttprequestgithub-api

Download zip file using java11 HttpClient.sendAsync()


I'm trying to download a zip file through a java program using GitHub API.

The program I'm using is the following:

public static void main(String[] args) {
        // create client
        HttpClient client = HttpClient.newHttpClient();

        // create request
        HttpRequest request = HttpRequest.newBuilder().uri(URI.create("https://api.github.com/repos/:owner/:repo/zipball/:ref")).build();

        // use the client to send the asynchronous request
        InputStream is = client.sendAsync(request, BodyHandlers.ofInputStream())
                .thenApply(HttpResponse::body).join();
        try {
            FileOutputStream out = new FileOutputStream("outputZipFile.zip");
            copy(is,out,1024);
            out.close();
        }catch(Exception e) {}
        
        
        
    }

    private static void copy(InputStream is, FileOutputStream out, int i) {
        // TODO Auto-generated method stub
        byte[] buf = new byte[i];
        try {
            int n = is.read(buf);
            while(n>=0) {
                out.write(buf,0,n);
                n=is.read(buf);
            }
            out.flush();
        }catch(IOException ioe) {
            System.out.println(ioe.getStackTrace());
        }
        
    }

When I try to run this I get empty body so the output file will be empty as well. I noticed that using HttpURLConnection insted of Java11 HttpClient makes it work but I'd prefer to use this Java11 feature in order to send asynchronous requests.

I can't understand what I'm doing wrong.

EDIT: The HttpURLConnection code I'm using at the moment is the following:

private void downloadVersion(String sha, String outputDestination) {
            try {
                URL url = new URL( getDownloadQuery(sha) );
                
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                if(authToken!=null) 
                    connection.setRequestProperty("Authorization", "Bearer " + authToken) ;
                connection.setRequestMethod("GET");
                
                InputStream in = connection.getInputStream();
    
                FileOutputStream out = new FileOutputStream(outputDestination);
                copy(in, out, 1024);
                out.close();
            } catch (Exception e) {}
            
        }

Solution

  • Your url (when set to correct github repos) may be returning redirect status 302. To make HTTP client follow redirects replace HttpClient client = HttpClient.newHttpClient() with use of HttpClient.newBuilder(). You can also simplify your code with try with resources and making use of InputStream.transferTo:

    HttpClient client = HttpClient.newBuilder().followRedirects(Redirect.ALWAYS).build();
    
    URI uri = URI.create("https://api.github.com/repos/:owner/:repo/zipball/:ref");
    HttpRequest request = HttpRequest.newBuilder().uri(uri).build();
    
    // use the client to send the asynchronous request
    InputStream is = client.sendAsync(request, BodyHandlers.ofInputStream())
            .thenApply(HttpResponse::body).join();
    try (FileOutputStream out = new FileOutputStream("outputZipFile.zip")) {
        is.transferTo(out);
    }