2009-12-10 23 views
71

No puedo entender por qué no se redirige a Java HttpURLConnection. Yo uso el siguiente código para obtener this page:URLConnection no sigue redirigir

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

Por otra parte, me da la siguiente respuesta (Parece que toda la razón!):

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 

Por desgracia, la variable res contiene el mismo URL y corriente contiene lo siguiente (obviamente, de Java HttpURLConnection no sigue redirigir!):

<!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> 

Respuesta

98

no creo que va a redirigir automáticamente de HTTP a HTTPS (o vice- versa).

Aunque sabemos que refleja HTTP, desde el punto de vista del protocolo HTTP, HTTPS es simplemente otro protocolo completamente diferente y desconocido. Sería inseguro seguir el redireccionamiento sin la aprobación del usuario.

Por ejemplo, supongamos que la aplicación está configurada para realizar autenticación de cliente automáticamente. El usuario espera navegar de forma anónima porque usa HTTP. Pero si su cliente sigue HTTPS sin preguntar, su identidad se revela al servidor.

+52

Gracias. Acabo de encontrar confiramción: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4620571. A saber: "Después de la discusión entre los ingenieros de Java Networking, se considera que no deberíamos seguir automáticamente la redirección de un protocolo a otro, por ejemplo, de http a https y viceversa, al hacerlo puede tener serias consecuencias de seguridad. para devolver las respuestas del servidor para la redirección. Compruebe el código de respuesta y el valor del campo del encabezado de ubicación para la información de redirección. Es responsabilidad de la aplicación seguir el redireccionamiento ". – Shcheklein

+1

¿Pero sigue la redirección de http a http o https a https? Incluso eso estaría mal. ¿No es así? – Enigma

+0

@Enigma Puede configurar ese comportamiento [globalmente] (http://docs.oracle.com/javase/7/docs/api/java/net/HttpURLConnection.html#setFollowRedirects (boolean)) o en un [por instancia ] (http://docs.oracle.com/javase/7/docs/api/java/net/HttpURLConnection.html#setInstanceFollowRedirects (boolean)) base. Por defecto, * does * follow redirects si el esquema no cambia. – erickson

-4

HttpURLConnection no es responsable de la manipulación la respuesta del objeto. Es el rendimiento esperado, capta el contenido de la URL solicitada. Depende de usted el usuario de la funcionalidad interpretar la respuesta. No puede leer las intenciones del desarrollador sin especificación.

+6

¿Por qué tiene setInstanceFollowRedirects en este caso?)) – Shcheklein

+0

Supongo que fue una función sugerida para agregar más tarde, tiene sentido ... mi comentario fue más de lo que se refleja hacia ... la clase está diseñada para ir y tomar contenido web y traerlo de vuelta ... personas Es posible que desee obtener mensajes que no sean HTTP 200. – monksy

24

Tiene algo llamado HttpURLConnection.setFollowRedirects(false) por casualidad?

Siempre se puede llamar

conn.setInstanceFollowRedirects(true); 

si usted quiere asegurarse de que no afecta al resto del comportamiento de la aplicación.

+0

Ooo ... no sabía nada de eso ... Buen hallazgo ... Estaba a punto de buscar la clase en caso de que existiera una lógica así ... Tiene sentido que devuelva ese encabezado dando el single responsabilidad principal .... ahora vuelve a responder las preguntas C#: P [Estoy bromeando] – monksy

+2

Tenga en cuenta que setFollowRedirects() debe invocarse en la clase, y no en una instancia. –

+2

@dldnh: Mientras que karlbecker_com tenía toda la razón al llamar 'setFollowRedirects' al tipo,' setInstanceFollowRedirects' es un método * instancia * y no se puede invocar en el tipo. –

-3

Es la respuesta correcta, pero usted sabe que tiene que conseguir la nueva ubicación de la respuesta, y usar eso como la url

5

Según lo mencionado por algunos de ustedes arriba, los setFollowRedirect y setInstanceFollowRedirects solo funcionan automáticamente cuando el protocolo redirigido es el mismo. es decir, de http a http y https a https.

setFolloRedirect está a nivel de clase y establece esto para todas las instancias de la conexión de url, mientras que setInstanceFollowRedirects es solo para una instancia determinada. De esta manera, podemos tener un comportamiento diferente para diferentes instancias.

me encontré con un muy buen ejemplo aquí http://www.mkyong.com/java/java-httpurlconnection-follow-redirect-example/

40

HttpURLConnection por design no va a redirigir automáticamente de HTTP a HTTPS (o viceversa). Seguir el redireccionamiento puede tener serias consecuencias de seguridad. SSL (por lo tanto HTTPS) crea una sesión que es única para el usuario. Esta sesión puede reutilizarse para múltiples solicitudes. Por lo tanto, el servidor puede rastrear todas las solicitudes realizadas desde una sola persona. Esta es una forma débil de identidad y es explotable. Además, el protocolo de enlace SSL puede solicitar el certificado del cliente. Si se envía al servidor, la identidad del cliente se entrega al servidor.

Como erickson señala, suponga que la aplicación está configurada para realizar autenticación de cliente automáticamente.El usuario espera navegar de forma anónima porque usa HTTP. Pero si su cliente sigue HTTPS sin preguntar, su identidad se revela al servidor.

Con eso entendido, aquí está el código que seguirá los redireccionamientos.

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(); 
    ... 
+0

Esta es solo una solución que funciona para más de 1 redireccionamientos. ¡Gracias! –

+0

¡Esto funciona muy bien para múltiples redireccionamientos (API HTTPS -> HTTP -> imagen HTTP)! Solución perfecta y simple – EricH206

+0

Solo le hago limitar el número de redireccionamientos; de lo contrario, puede entrar en un bucle infinito –

Cuestiones relacionadas