109

HttpURLConnectionJavaがHTTPからHTTPSURLへのHTTPリダイレクトに従わない理由がわかりません。次のコードを使用して、https: //httpstat.us/のページを取得します。

import java.net.URL;
import java.net.HttpURLConnection;
import java.io.InputStream;

public class Tester {

    public static void main(String argv[]) throws Exception{
        InputStream is = null;

        try {
            String httpUrl = "http://httpstat.us/301";
            URL resourceUrl = new URL(httpUrl);
            HttpURLConnection conn = (HttpURLConnection)resourceUrl.openConnection();
            conn.setConnectTimeout(15000);
            conn.setReadTimeout(15000);
            conn.connect();
            is = conn.getInputStream();
            System.out.println("Original URL: "+httpUrl);
            System.out.println("Connected to: "+conn.getURL());
            System.out.println("HTTP response code received: "+conn.getResponseCode());
            System.out.println("HTTP response message received: "+conn.getResponseMessage());
       } finally {
            if (is != null) is.close();
        }
    }
}

このプログラムの出力は次のとおりです。

元のURL:http://httpstat.us/301
接続先:http://httpstat.us/301
受信したHTTP応答コード:301
受信したHTTP応答メッセージ:永続的に移動

http://httpstat.us/301へのリクエストは、次の(短縮された)応答を返します(これは絶対に正しいようです!):

HTTP/1.1 301 Moved Permanently
Cache-Control: private
Content-Length: 21
Content-Type: text/plain; charset=utf-8
Location: https://httpstat.us

残念ながら、JavaHttpURLConnectionはリダイレクトに従いません!

元のURLをHTTPS( https://httpstat.us/301)に変更すると、Java期待どおりにリダイレクトに従うことに注意してください!?

4

6 に答える 6

128

リダイレクトは、同じプロトコルを使用する場合にのみ実行されます。(ソースfollowRedirect()メソッドを参照してください。)このチェックを無効にする方法はありません。

HTTPを反映していることはわかっていますが、HTTPプロトコルの観点からは、HTTPSは他のまったく異なる未知のプロトコルです。ユーザーの承認なしにリダイレクトを追跡することは安全ではありません。

たとえば、アプリケーションがクライアント認証を自動的に実行するように設定されているとします。ユーザーは、HTTPを使用しているため、匿名でネットサーフィンすることを期待しています。しかし、彼のクライアントが質問せずにHTTPSをフォローしている場合、彼のIDはサーバーに公開されます。

于 2009-12-10T22:05:46.090 に答える
61

設計上、HttpURLConnectionはHTTPからHTTPSに(またはその逆に)自動的にリダイレクトされません。リダイレクトに従うと、セキュリティに深刻な影響を与える可能性があります。SSL(したがってHTTPS)は、ユーザーに固有のセッションを作成します。このセッションは、複数のリクエストに再利用できます。したがって、サーバーは1人の人物からのすべての要求を追跡できます。これはアイデンティティの弱い形式であり、悪用可能です。また、SSLハンドシェイクはクライアントの証明書を要求できます。サーバーに送信されると、クライアントのIDがサーバーに渡されます。

ericksonが指摘しているように、アプリケーションがクライアント認証を自動的に実行するように設定されているとします。ユーザーは、HTTPを使用しているため、匿名でネットサーフィンすることを期待しています。しかし、彼のクライアントが質問せずにHTTPSをフォローしている場合、彼のIDはサーバーに公開されます。

プログラマーは、HTTPからHTTPSにリダイレクトする前に、クレデンシャル、クライアント証明書、またはSSLセッションIDが送信されないようにするための追加の手順を実行する必要があります。デフォルトでは、これらを送信します。リダイレクトによってユーザーが傷つく場合は、リダイレクトに従わないでください。これが、自動リダイレクトがサポートされていない理由です。

これを理解した上で、リダイレクトに従うコードを次に示します。

  URL resourceUrl, base, next;
  Map<String, Integer> visited;
  HttpURLConnection conn;
  String location;
  int times;

  ...
  visited = new HashMap<>();

  while (true)
  {
     times = visited.compute(url, (key, count) -> count == null ? 1 : count + 1);

     if (times > 3)
        throw new IOException("Stuck in redirect loop");

     resourceUrl = new URL(url);
     conn        = (HttpURLConnection) resourceUrl.openConnection();

     conn.setConnectTimeout(15000);
     conn.setReadTimeout(15000);
     conn.setInstanceFollowRedirects(false);   // Make the logic below easier to detect redirections
     conn.setRequestProperty("User-Agent", "Mozilla/5.0...");

     switch (conn.getResponseCode())
     {
        case HttpURLConnection.HTTP_MOVED_PERM:
        case HttpURLConnection.HTTP_MOVED_TEMP:
           location = conn.getHeaderField("Location");
           location = URLDecoder.decode(location, "UTF-8");
           base     = new URL(url);               
           next     = new URL(base, location);  // Deal with relative URLs
           url      = next.toExternalForm();
           continue;
     }

     break;
  }

  is = conn.openStream();
  ...
于 2014-09-25T18:59:05.313 に答える
27

HttpURLConnection.setFollowRedirects(false)万が一、何か呼ばれたことがありますか?

いつでも電話できます

conn.setInstanceFollowRedirects(true);

アプリの残りの動作に影響を与えないようにする場合。

于 2009-12-10T21:41:17.480 に答える
7

上記の一部の人が述べたように、setFollowRedirectとsetInstanceFollowRedirectsは、リダイレクトされたプロトコルが同じ場合にのみ自動的に機能します。つまり、httpからhttpおよびhttpsからhttpsへ。

setFolloRedirectはクラスレベルであり、これをurl接続のすべてのインスタンスに設定しますが、setInstanceFollowRedirectsは特定のインスタンスにのみ適用されます。このようにして、インスタンスごとに異なる動作をすることができます。

ここで非常に良い例を見つけました http://www.mkyong.com/java/java-httpurlconnection-follow-redirect-example/

于 2013-10-01T06:12:11.113 に答える
3

別のオプションは、 ApacheHttpComponentsクライアントを使用することです。

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

サンプルコード:

CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("https://media-hearth.cursecdn.com/avatars/330/498/212.png");
CloseableHttpResponse response = httpclient.execute(httpget);
final HttpEntity entity = response.getEntity();
final InputStream is = entity.getContent();
于 2018-07-06T16:16:57.853 に答える
-5

HTTPUrlConnectionは、オブジェクトの応答の処理を担当しません。期待通りのパフォーマンスで、リクエストしたURLのコンテンツを取得します。応答を解釈する機能のユーザーはあなた次第です。仕様なしでは開発者の意向を読み取ることはできません。

于 2009-12-10T21:41:08.650 に答える