URLConnection不遵循重定向

Shc*_*ein 92 java https redirect httpurlconnection http-redirect

我无法理解为什么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 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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

而且,我收到以下回复(看起来绝对正确!):

Original URL: http://httpstat.us/301
Connected to: http://httpstat.us/301
HTTP response code received: 301
HTTP response message received: Moved Permanently

不幸的是,HttpURLConnection变量包含相同的URL,并且流包含以下内容(显然,Java HttpURLConnection不遵循重定向!):

HTTP/1.1 301 Moved Permanently
Cache-Control: private
Content-Length: 21
Content-Type: text/plain; charset=utf-8
Location: https://httpstat.us
Run Code Online (Sandbox Code Playgroud)

eri*_*son 112

我认为它不会自动从HTTP重定向到HTTPS(反之亦然).

尽管我们知道它反映了HTTP,但从HTTP协议的角度来看,HTTPS只是其他一些完全不同的未知协议.未经用户批准,遵循重定向是不安全的.

例如,假设应用程序设置为自动执行客户端身份验证.用户希望匿名冲浪,因为他正在使用HTTP.但如果他的客户端在没有询问的情况下跟踪HTTPS,则会向服务器显示其身份.

  • 谢谢.我刚刚找到了confiramtion:http://bugs.sun.com/bugdatabase/view_bug.do?video_id = 4620571.即:"经过Java网络工程师之间的讨论,我们觉得我们不应该自动遵循从一个协议到另一个协议的重定向,例如,从http到https,反之亦然,这样做可能会产生严重的安全后果.因此修复是返回重定向的服务器响应.检查响应代码和位置标题字段值以获取重定向信息.应用程序有责任遵循重定向." (59认同)
  • 没有人在HTTPS上设置自动登录,然后期望HTTP是"匿名的".这是荒谬的.遵循从HTTP到HTTPS的重定向是非常安全和正常的(不是相反).这只是一个典型的糟糕的Java API. (17认同)
  • Java Networking工程师可以提供setFollowTransProtocol(true)选项,因为如果我们需要它,我们无论如何都会编程.仅供参考的网络浏览器,curl和wget,可能会更多地遵循从HTTP到HTTPS的重定向,反之亦然. (7认同)
  • @JoshuaDavis是的,它仅适用于重定向到同一协议.即使设置了重定向标志,`HttpURLConnection`也不会自动跟随重定向到不同的协议. (5认同)
  • 但它是否遵循从http重定向到http或https到https?即便如此也是错的.不是吗? (2认同)

Nat*_*han 50

设计中的 HttpURLConnection 不会自动从HTTP重定向到HTTPS(反之亦然).重定向后可能会产生严重的安全后果.SSL(因此HTTPS)创建一个对用户唯一的会话.此会话可以重复用于多个请求.因此,服务器可以跟踪从单个人做出的所有请求.这是一种弱的身份形式,可以利用.此外,SSL握手可以请求客户端的证书.如果发送到服务器,则将客户端的标识提供给服务器.

正如erickson指出的那样,假设应用程序已设置为自动执行客户端身份验证.用户希望匿名冲浪,因为他正在使用HTTP.但如果他的客户端在没有询问的情况下跟踪HTTPS,则会向服务器显示其身份.

有了这个,这里的代码将遵循重定向.

  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();
  ...
Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 26

什么事情HttpURLConnection.setFollowRedirects(false)有机会?

你总是可以打电话

conn.setInstanceFollowRedirects(true);
Run Code Online (Sandbox Code Playgroud)

如果您想确保不影响应用程序的其余行为.

  • 请注意,应该在类上调用setFollowRedirects(),而不是在实例上调用. (2认同)
  • @dldnh:虽然karlbecker_com在类型上调用`setFollowRedirects`是绝对正确的,但是`setInstanceFollowRedirects`是一个*instance*方法,不能在类型上调用. (2认同)

小智 6

正如上面的一些人所提到的,setFollowRedirect和setInstanceFollowRedirects仅在重定向协议相同时自动工作.即从http到http和https到https.

setFolloRedirect处于一流水平,并将此的URL连接的所有实例,而setInstanceFollowRedirects是只在一定的实例.这样我们就可以为不同的实例提供不同的行为.

我在这里找到了一个很好的例子 http://www.mkyong.com/java/java-httpurlconnection-follow-redirect-example/


Kor*_*gay 6

另一种选择是使用Apache HttpComponents Client

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>
Run Code Online (Sandbox Code Playgroud)

示例代码:

CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpget = new HttpGet("https://media-hearth.cursecdn.com/avatars/330/498/212.png");
CloseableHttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
Run Code Online (Sandbox Code Playgroud)