2016-11-16 7 views
0

これはちょっと変わったものですが、私はこの問題の原因と解決方法を見つけるのに十分な研究を行っています。私の目的は、ログインが必要なセキュリティ保護されたURLからzipファイルをダウンロードすることです。 バージョン4.3.6のapache httpClient maven依存関係を使用すると、すべてが完璧に動作します。しかし、私のaws-sdk-java-core-maven依存性にもhttpclient依存性があり、v4.3.6を使用するとaws-sdk-javaがNoSuchMethodランタイム例外について不平を言ってしまうため、このバージョンを使用することはできません。私はこの問題を理解しています。その理由は、Apacheのhttpclient v4.3.6の依存関係は、aws-sdk-java-core依存関係で使用されているバージョン(4.5.1)よりもmaven依存ツリーで最も近いためです。とにかく、これについてもっと詳しく説明します。なぜなら、すべてのものをmaven依存関係の1つのバージョンで動作させ、同じjarの複数のバージョンを使用しないようにする必要があるからです。 元の質問に戻るv4.3.6を使用できないので、v4.5.1を使用するようにコードに指示しました。私がhttpclient v4.5.1を使用すると、リクエストしたhttps urlにあるzipファイルを返すのではなく、次のHTMLコンテンツが返されます。zipファイルのダウンロードはapache httpclient v4.3.6で動作しますが、他のバージョンでは失敗します

私はv4.3.6を使用すると、応答が私に期待される応答としてzipファイルを与えます。私はコードを追加してこのhtmlコンテンツを手動で提出しようとしましたが、応答はそのままです。 ファイルのダウンロード元のコードは以下のとおりです。

@Component 
public class FileDAO { 

    public static void main(String args[]) throws Exception{ 
     new FileDAO().loadFile("https://some_url.domain.com/zipball/master","myfile.zip"); 
    } 


    public String loadFile(String url, String fileName) throws ClientProtocolException, IOException { 

     HttpClient client = login(); 
     HttpResponse response = client.execute(new HttpGet(url)); 
     int statusCode = response.getStatusLine().getStatusCode(); 
     if (statusCode == 200) { 
      String unzipToFolderName = fileName.replace(".", "_"); 
      FileOutputStream outputStream = new FileOutputStream(new File(fileName)); 
      writeToFile(outputStream, response.getEntity().getContent());    
      return unzipToFolderName; 
     } else { 
      throw new RuntimeException("error downloading file, HTTP Status code: " + statusCode); 
     } 
    } 

    private void writeToFile(FileOutputStream outputStream, InputStream inputStream) { 
     try { 
      int read = 0; 
      byte[] bytes = new byte[1024]; 
      while ((read = inputStream.read(bytes)) != -1) { 
       outputStream.write(bytes, 0, read); 
      } 
     } catch (Exception ex) { 
      throw new RuntimeException("error writing zip file, error message : " + ex.getMessage(), ex); 
     } finally { 
      try { 
       outputStream.close(); 
       inputStream.close(); 
      } catch (Exception ex) {} 
     } 
    } 

    private HttpClient login() throws IOException { 
     HttpClient client = getHttpClient(); 

     HttpResponse response = client.execute(new HttpGet("https://some_url.domain.com")); 
     String responseBody = EntityUtils.toString(response.getEntity()); 
     Document doc = Jsoup.parse(responseBody); 
     org.jsoup.select.Elements inputs = doc.getElementsByTag("input"); 
     int statusCode = response.getStatusLine().getStatusCode(); 
     if (statusCode == 200) { 
      HttpPost httpPost = new HttpPost("https://some_url.domain.com/saml/consume"); 
      List<NameValuePair> data = new ArrayList<NameValuePair>(); 
      data.add(new BasicNameValuePair("SAMLResponse", doc.select("input[name=SAMLResponse]").val())); 
      data.add(new BasicNameValuePair("RelayState", doc.select("input[name=RelayState]").val())); 
      httpPost.setEntity(new UrlEncodedFormEntity(data)); 
      HttpResponse logingResponse = client.execute(httpPost); 
      int loginStatusCode = logingResponse.getStatusLine().getStatusCode(); 
      if (loginStatusCode != 302) { 
       throw new RuntimeException("clone repo dao. error during login, HTTP Status code: " + loginStatusCode); 
      } 
     } 
     return client; 
    } 

    private HttpClient getHttpClient() { 
     CredentialsProvider provider = new BasicCredentialsProvider(); 
     UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("userId", "password"); 
     provider.setCredentials(AuthScope.ANY, credentials); 
     return HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build(); 
    } 
} 

私はまだ4.3.6以外のバージョンのhttpclientで問題が起こっていると分析しています。同じコードは4.3.6で動作しますが、4.3.6より上のバージョンでは動作しません。 本当にありがとうございます。皆さん、ありがとうございました。

答えて

1

問題を解決しました。深刻なログをデバッグしてApacheのhttpclient文書を調べたところ、この問題を解決できました。 v4.3.6用とv4.5.2用の2つのサーバーログを作成する必要がありました。私はサーバーのログを比較し始め、その原因がCookieの種類であることがわかりました。古いバージョンのCookieタイプは(自動的に)BEST_MATCHとして設定され、機能していました。しかし、v4.5.2では、BEST_MATCHクッキータイプはapacheから廃止されました。私はいくつかのコードを追加した後でcookie設定を試してきましたが、サーバレスポンスによって送られたクッキーが、クライアントコードで設定したDEFAULTクッキータイプと一致しませんでした。 Cookieが正しく設定されていないため、レスポンスがzipファイルではなくSAMLレスポンス(ログインページ)に戻ってきた理由です。

のApache cookie specは、クッキーの仕様については、この意見:

デフォルト:デフォルトクッキーポリシーはと共に送られたクッキーの特性に基づいて、いずれかのRFC 2965、RFC 2109またはNetscapeドラフト準拠した実装をピックアップ合成方針ですHTTP応答(バージョン属性など、現在は廃止)このポリシーは、HttpClientの次のマイナーリリースでの標準(RFC 6265準拠)の実装を支持して廃止される予定です。 標準厳しい:RFC 6265で定義されて行儀プロファイルの構文とセマンティクスに準拠国家管理政策、セクション4

私はモードとすべてが最新バージョンで作業を開始しSTANDARD_STRICTにクッキーの設定を更新4.5.2。

private CloseableHttpClient getHttpClient() { 
    CredentialsProvider provider = new BasicCredentialsProvider(); 
    UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(gitUserId, gitPassword); 
    provider.setCredentials(AuthScope.ANY, credentials); 
    RequestConfig config = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT).build(); 
    return HttpClientBuilder.create().setDefaultCredentialsProvider(provider).setDefaultRequestConfig(config).setRedirectStrategy(new LaxRedirectStrategy()).build(); 
} 
:ここ

が更新getHttpClient()メソッドであります

関連する問題