URLConnection ne suit pas Redirect

Je ne comprends pas pourquoi le HttpURLConnection de Java ne suit pas la redirection. J'utilise le code suivant pour obtenir cette page :

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

de plus, je reçois la réponse suivante (cela semble tout à fait juste!):

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

malheureusement, la variable res contient la même URL et le flux contient ce qui suit (évidemment, HttpURLConnection de Java ne suit pas redirect!):

<!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>
79
demandé sur Nathan 2009-12-11 00:38:46

6 réponses

Je ne pense pas qu'il redirigera automatiquement de HTTP vers HTTPS (ou vice-versa).

même si nous savons qu'il est un miroir HTTP, du point de vue du protocole HTTP, HTTPS est juste un autre protocole inconnu, complètement différent. Il serait dangereux de suivre la redirection sans l'approbation de l'utilisateur.

par exemple, supposons que l'application est configurée pour effectuer l'authentification du client automatiquement. L'utilisateur s'attend à surfer de manière anonyme parce qu'il utilise le protocole HTTP. Mais si son client suit HTTPS sans le demander, son identité est révélée au serveur.

101
répondu erickson 2009-12-10 22:05:46

HttpURLConnection par design ne redirigera pas automatiquement HTTP vers HTTPS (ou vice versa). Le fait de suivre la redirection peut avoir de graves conséquences sur la sécurité. SSL (donc HTTPS) crée une session unique pour l'utilisateur. Cette session peut être réutilisée pour des requêtes multiples. Ainsi, le serveur peut suivre toutes les requêtes faites à partir d'une seule personne. C'est une forme d'identité faible et exploitable. En outre, la poignée de main SSL peut demander au client certificat. S'il est envoyé au serveur, alors l'identité du client est donnée au serveur.

comme le souligne erickson , supposons que l'application soit configurée pour effectuer automatiquement l'authentification du client. L'utilisateur s'attend à surfer anonymement parce qu'il utilise HTTP. Mais si son client suit HTTPS sans le demander, son identité est révélée au serveur.

avec cela compris, voici le code qui suivra le rediriger.

  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();
  ...
45
répondu Nathan 2017-11-30 18:42:54

est-ce que quelque chose s'appelle HttpURLConnection.setFollowRedirects(false) par hasard?

vous pouvez toujours appeler

conn.setInstanceFollowRedirects(true);

si vous voulez vous assurer que vous n'affectent pas le reste du comportement de l'application.

26
répondu Jon Skeet 2013-04-13 10:41:31

comme mentionné par certains d'entre vous ci-dessus, le setFollowRedirect et le setInstanceFollowRedirects ne fonctionnent que lorsque le protocole redirigé est identique . ie de http à http et https à https.

setFolloRedirect est au niveau de la classe et le définit pour toutes les instances de la connexion url, alors que setInstanceFollowRedirects est seulement pour une instance donnée. De cette façon, nous pouvons avoir un comportement différent pour différentes instances.

j'ai trouvé un très bon exemple ici http://www.mkyong.com/java/java-httpurlconnection-follow-redirect-example /

5
répondu Shalvika 2013-10-01 06:12:11

une autre option peut être d'utiliser Apache HttpComponents Client :

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

code échantillon:

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();
1
répondu Koray Tugay 2018-07-09 13:18:47

HTTPUrlConnection n'est pas responsable du traitement de la réponse de l'objet. C'est performance comme prévu, il saisit le contenu de L'URL demandée. C'est à vous, l'utilisateur de la fonctionnalité pour interpréter la réponse. Il n'est pas en mesure de lire les intentions du développeur sans spécification.

-4
répondu monksy 2009-12-10 21:41:08