URLConnection не следует перенаправление


Я не могу понять, почему Java HttpURLConnection не следует перенаправить. Я использую следующий код, чтобы получить на этой странице:

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 bitlyUrl = "http://bit.ly/4hW294";
            URL resourceUrl = new URL(bitlyUrl);
            HttpURLConnection conn = (HttpURLConnection)resourceUrl.openConnection();
            conn.setConnectTimeout(15000);
            conn.setReadTimeout(15000);
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.0.11) Gecko/2009060215 Firefox/3.0.11 (.NET CLR 3.5.30729)");
            conn.connect();
            is = conn.getInputStream();
            String res = conn.getURL().toString();
            if (res.toLowerCase().contains("bit.ly"))
                System.out.println("bit.ly is after resolving: "+res);
       }
       catch (Exception e) {
           System.out.println("error happened: "+e.toString());
       }
       finally {
            if (is != null) is.close(); 
        }
    }
}

более того, я получаю следующий ответ (это кажется абсолютно правильным!):

GET /4hW294 HTTP/1.1
Host: bit.ly
Connection: Keep-Alive
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; ru-RU; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)
HTTP/1.1 301 Moved
Server: nginx/0.7.42
Date: Thu, 10 Dec 2009 20:28:44 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
Location: https://www.myganocafe.com/CafeMacy
MIME-Version: 1.0
Content-Length: 297

к сожалению,res переменная содержит тот же URL и поток содержит следующее (очевидно, Java HttpURLConnection не следует перенаправить!):

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML>
<HEAD>
<TITLE>Moved</TITLE>
</HEAD>
<BODY>
<H2>Moved</H2>
<A HREF="https://www.myganocafe.com/CafeMacy">The requested URL has moved here.</A>
<P ALIGN=RIGHT><SMALL><I>AOLserver/4.5.1 on http://127.0.0.1:7400</I></SMALL></P>
</BODY>
</HTML>
6 79

6 ответов:

Я не думаю, что он будет автоматически перенаправлять с HTTP на HTTPS (или наоборот).

хотя мы знаем, что он отражает HTTP, с точки зрения протокола HTTP HTTPS-это просто какой-то другой, совершенно другой, неизвестный протокол. Было бы небезопасно следовать перенаправлению без одобрения пользователя.

например, предположим, что приложение настроено для автоматического выполнения проверки подлинности клиента. Пользователь ожидает, что будет заниматься серфингом анонимно, потому что он использует HTTP. Но если его клиент следует HTTPS без запроса, его личность раскрывается серверу.

HttpURLConnection by конструкция не будет автоматически перенаправлять с HTTP на HTTPS (или наоборот). После перенаправления может иметь серьезные последствия для безопасности. SSL (следовательно, HTTPS) создает сеанс, который является уникальным для пользователя. Этот сеанс можно повторно использовать для нескольких запросов. Таким образом, сервер может отслеживать все запросы от одного человека. Это слабая форма идентичности и ее можно использовать. Кроме того, SSL-квитанция может запросить сертификат клиента. Если отправляется на сервер, после чего идентификатор клиента передается на сервер.

Как Эриксон указывает, предположим, что приложение настроено для автоматического выполнения аутентификации клиента. Пользователь ожидает, что будет заниматься серфингом анонимно, потому что он использует HTTP. Но если его клиент следует HTTPS без запроса, его личность раскрывается серверу.

С этим понятно, вот код, который будет следовать перенаправления.

  URL resourceUrl, base, next;
  HttpURLConnection conn;
  String location;

  ...

  while (true)
  {
     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();
  ...

есть что-то под названием HttpURLConnection.setFollowRedirects(false) случайно?

вы всегда можете позвонить

conn.setInstanceFollowRedirects(true);

Если вы хотите, чтобы убедиться, что вы не влияете на остальную часть поведения приложения.

Как упоминалось некоторыми из вас выше, setFollowRedirect и setInstanceFollowRedirects работают автоматически только тогда, когда перенаправленный протокол одинаков . т. е. от http к http и https к https.

setFolloRedirect находится на уровне класса и устанавливает это для всех экземпляров url-соединения, тогда как setInstanceFollowRedirects только для данного экземпляра. Таким образом мы можем иметь различное поведение для различных случаев.

Я нашел очень хороший пример здесь http://www.mkyong.com/java/java-httpurlconnection-follow-redirect-example/

еще один вариант можно использовать Apache HttpComponents Client:

<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();

HTTPUrlConnection не несет ответственности за обработку ответа объекта. Это производительность, как и ожидалось, он захватывает содержимое запрошенного URL. Это до вас пользователь функциональности, чтобы интерпретировать ответ. Он не в состоянии прочитать намерения разработчика без спецификации.