javaのHttpClientでファイルをダウンロード(proxy経由とBASIC認証付き)

javaのバッチプログラムから、外部のサーバにアクセスして、Getメソッドでzipファイルをダウンロードすることになったので、調査したことを書いておきます。

javaプログラムからHttpでサーバにアクセスして情報取得するライブラリはいくつかあるのですが、「Apache HttpComponents」プロジェクトの「HttpClient」が使いやすかったです。

以前は「The Commons HttpClient」プロジェクトだったようですが、それがこちらに置き換わったようですね。

このプロジェクトは

「java.net」等のパッケージを使って頑張ってプログラムを書くのもいいんだけど、もう少し利用しやすい形でHTTPをハンドリングするアプリから利用できないか

という理念に基づいて運営されていて、通常のGET、POSTはもちろん、proxy経由でのWebアクセスや、BASIC認証、SSLでのアクセスなど、一般的に利用する方法のほとんどを網羅しています。

今回、以下に簡単なサンプルを載せておきます。

サンプルソースの下の方に簡単に説明(ポイント)を付けておきますので、ぜひ読んでください。

まずは、ライブラリを用意する必要がありますね。

HttpClientパッケージを用意

Apache HttpComponentsプロジェクトのページから必要なjarをダウンロードしてきましょう。今回は、「httpcomponents-client-4.1.3-bin.zip」にしました。

次に、eclipseか何かでサンプルのプロジェクトを作成し、上記zipを解凍して出来るjar

・commons-codec-1.4.jar ・commons-logging-1.1.1.jar ・httpclient-4.1.3.jar ・httpclient-cache-4.1.3.jar ・httpcore-4.1.4.jar ・httpmime-4.1.3.jar

をプロジェクトのBuildPathに追加しておきます。

サンプルソースとポイント

では、サンプルのソースです。

package com.koji;
 
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
 
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
 
public class HttpConnect {
 
private static final String PROXY_HOST = "xxxxxxxxx.co.jp";
private static final int PROXY_PORT = 8080;
 
private static final String TARGET_HOST = "xxxxxxxxxxx.jp";
private static final int TARGET_PORT = 80;
 
private static final String BASIC_USER= "sampleUser";
private static final String BASIC_PASS= "samplePassword";
 
private static final String GET_PARAM= "/xxxxxxxxx/xxxxxx?ID=yyyyy&2ID2=wwwww";
 
    public final static void main(String[] args) throws Exception {
 
    DefaultHttpClient httpclient = null;
    HttpHost proxy = null;
    HttpHost targetHost = null;
 
    InputStream is = null;
    FileOutputStream out = null;
    HttpEntity entity = null;
 
        try {
            httpclient = new DefaultHttpClient();
 
            proxy = new HttpHost(PROXY_HOST, PROXY_PORT, "http");
            httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
 
            targetHost = new HttpHost(TARGET_HOST, TARGET_PORT, "http");
 
            httpclient.getCredentialsProvider().setCredentials(
                new AuthScope(targetHost.getHostName(), targetHost.getPort()),
                new UsernamePasswordCredentials(BASIC_USER, BASIC_PASS));
 
            AuthCache authCache = new BasicAuthCache();
            BasicScheme basicAuth = new BasicScheme();
            authCache.put(targetHost, basicAuth);
            BasicHttpContext localcontext = new BasicHttpContext();
            localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);
 
 
            HttpGet httpget = new HttpGet(GET_PARAM);
 
            HttpResponse response = httpclient.execute(targetHost, httpget, localcontext);
            entity = response.getEntity();
 
            System.out.println("response=" + response.getAllHeaders());
 
            // レスポンスヘッダーの取得(ファイルが無かった場合などは404)
            System.out.println("StatusCode=" + response.getStatusLine().getStatusCode());
 
            if(response.getStatusLine().getStatusCode() != 200 ){
 
            System.out.println("StatusCode:" + response.getStatusLine().getStatusCode());
                return;
            }
 
            Header[] headers = response.getAllHeaders();
                for (Header header : headers) {
                System.out.println(header.getName() + ": " + header.getValue());
            }
 
            // entityが取れなかった場合は、Connectionのことは心配しないでもOK
            if (entity != null) {
 
                System.out.println(EntityUtils.toString(entity));
 
                is = entity.getContent();
                System.out.println("length: " + entity.getContentLength());
 
                File file = new File("C:tttt.zip"); // 保存先
                out = new FileOutputStream(file, false);
 
                int b;
                while((b = is.read()) != -1){
                    out.write(b);
                }
 
                out.close();
                is.close();
 
                EntityUtils.consume(entity);
                //depriciated
                entity.consumeContent();
            }
 
            System.out.println("ダウンロードしました。");
 
        }catch (FileNotFoundException e) {
            // Fileオブジェクト生成時の例外捕捉
            e.printStackTrace();
 
        } catch (IOException ioe) {
            ioe.printStackTrace();
 
        }finally {
            httpclient.getConnectionManager().shutdown();
            try {
                if(out != null){
                    out.close();
            }
            if(is != null){
                is.close();
            }
            } catch(IOException e) {

            e.printStackTrace();
            }
 
        }
    }
}

proxy経由で接続できるようにするには

proxy = new HttpHost(PROXY_HOST, PROXY_PORT, “http”);
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);

この2行を追加するだけです。proxyを経由しない場合はコメントアウトしてください。

BASIC認証経由で接続するには、

httpclient.getCredentialsProvider().setCredentials(
new AuthScope(targetHost.getHostName(), targetHost.getPort()),
new UsernamePasswordCredentials(BASIC_USER, BASIC_PASS));

を設定します。UsernamePasswordCredentialはCredentialsインタフェースを実装したクラスで、どの認証情報を使用するかで異なります。

BASIC認証の場合はこのクラスですが、他にNT認証用、Digest認証用などを利用できます。
AuthScopeは意図したサーバ以外に誤って認証情報を送信しないように範囲を指定します。気にしないのであれば「AuthScope.ANY」でも良いですが。。。

AuthCacheはこのコンテキストに認証情報のキャッシュを追加します。

AuthCache authCache = new BasicAuthCache();
BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);
BasicHttpContext localcontext = new BasicHttpContext();
localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);

一度認証にクリアしてしまえば、同じコンテキスト内なら、再度認証する必要はなくなります。  

entity.consumeContent();

はdepriciatedになっています。EntityUtilsクラスのconsumeメソッドを利用しましょう。