使用HttpClient 4.1.1避免循环重定向

19

我如何使用HttpClient 4.1.1避免循环重定向?因为我遇到了以下错误:

executing requestGET http://home.somehost.com/Mynet/pages/cHome.xhtml HTTP/1.1
org.apache.http.client.ClientProtocolException
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:822)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
    at edu.uci.ics.crawler4j.url.WebURL.setURL(WebURL.java:122)
    at edu.uci.ics.crawler4j.crawler.CrawlController.addSeed(CrawlController.java:207)
    at edu.uci.ics.crawler4j.example.advanced.Controller.main(Controller.java:31)
Caused by: org.apache.http.client.CircularRedirectException: Circular redirect to 'http://home.somehost.com/Mynet/pages/Home.xhtml'
    at org.apache.http.impl.client.DefaultRedirectStrategy.getLocationURI(DefaultRedirectStrategy.java:168)
    at org.apache.http.impl.client.DefaultRedirectStrategy.getRedirect(DefaultRedirectStrategy.java:193)
    at org.apache.http.impl.client.DefaultRequestDirector.handleResponse(DefaultRequestDirector.java:1021)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:482)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)

这是我的代码...

DefaultHttpClient client = null;

        try
        {
            // Set url
            //URI uri = new URI(url.toString());

            client = new DefaultHttpClient();

            client.getCredentialsProvider().setCredentials(
                    new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM),
                    new UsernamePasswordCredentials("test", "test"));


            URL url1 = new URL (url);
            HttpURLConnection connection = (HttpURLConnection) url1.openConnection();
            connection.setFollowRedirects(false);

            HttpGet request = new HttpGet(url);
            final HttpParams params = new BasicHttpParams();
            HttpClientParams.setRedirecting(params, false);
            HttpContext context = new BasicHttpContext();

            System.out.println("----------------------------------------");
            System.out.println("executing request" + request.getRequestLine());
            HttpResponse response = client.execute(request, context);
            HttpEntity entity = response.getEntity();


            System.out.println(response.getStatusLine());
                    InputStream content = entity.getContent();
                    BufferedReader in   = 
                        new BufferedReader (new InputStreamReader (content));
                    String line;
                    while ((line = in.readLine()) != null) {
                       // System.out.println(line);
                    }
                } catch(Exception e) {
                    e.printStackTrace();
                }

你确定你能避免它吗?如果确实存在循环反射,抛出异常似乎是一种合理的指示方式。 - nos
@nos 感谢回复。我在循环重定向时收到了相同的URL。但是,如果我在浏览器中输入该URL,则会从服务器返回三个响应,均为相同的URL。第一个是302 Moved tempo,第二个是302 found,第三个是200 ok,都是使用相同的URL...而我想获取此URL的内容。 - arsenal
6个回答

36
你可以将ClientPNames.ALLOW_CIRCULAR_REDIRECTS设置为true,这样会允许重定向到相同的位置。
  client.getParams().setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true); 

请查看更多信息 这里


8
当前版本已经废弃该方法,请改用RequestConfig.custom().setCircularRedirectsAllowed(true).build()。 - keiki
实际上,这只是为了防止 HttpClient 抛出重定向错误。这意味着重定向仍在发生?正如 Adam 所提到的,这是否需要在服务器上进行永久修复? - Ajith M A
我仍然收到以下错误:Caused by: org.apache.http.client.RedirectException: Maximum redirects (50) exceeded - gursahib.singh.sahni
@anonymous 当然。您的Web服务器配置不正确,并且存在重定向循环(即使在50个请求之后,在这种情况下服务器仍在重定向您)。这是客户端无法解决的问题。 - nos
我不能增加重定向计数吗?找不到任何方法... 如果Web服务器配置错误,那么Web浏览器如何能够正常打开它?这是URL:http://www.wsj.com/video/khorasan-meet-the-new-us-terrorist-target/157FA4EF-D44F-49BA-938B-002A91A090A3.html - gursahib.singh.sahni
1
一个浏览器会发送其他HTTP头,例如User-Agent:,这可能会使服务器行为不同(例如页面上的wget获取404)。如果50个重定向没有解决问题,增加重定向次数不太可能解决问题,但您可以通过设置ClientPNames.MAX_REDIRECTS参数来增加重定向次数。[(http://hc.apache.org/httpcomponents-client-4.2.x/tutorial/html/httpagent.html)] - nos

4

您可以尝试以下方法:

RequestConfig requestConfig = RequestConfig.custom()
                              .setCircularRedirectsAllowed(true)
                              .build();

HttpClient httpClient = HttpClients.custom()
                        .setDefaultRequestConfig(requestConfig)
                        .setRedirectStrategy(new LaxRedirectStrategy())
                        .build();

HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);

3
您刚刚避免了它。HttpClient检测到了循环重定向并抛出了异常。如果没有“避免”,它将会无限制地重定向(直到您决定终止进程)。如果服务器响应是这样的,那么就没有太多其他选择了。

唯一真正避免循环重定向循环的方法是修复服务器。

如果您想知道发生了什么(比如为什么在浏览器中似乎工作正常但从程序中不行),请尝试打开一些额外的HttpClient日志记录。特别是,请确保您可以看到来回发送的所有HTTP标头。然后,当您在浏览器中进行相同的请求时,可以查看正在进行的对话,注意差异。可能是缺少cookie、疯狂的浏览器检测等等......

有许多跟踪浏览器通信的方法。以下是我经常使用的一些方法,按照难易程度排序(仅供参考):

  • Firefox + HttpFox (或 LiveHttpHeaders,Firebug,等等...)
  • Fiddler (仅限Windows)
  • Wireshark/tcpdump

对于低级测试,请尝试使用telnet(除非您使用Windows,在这种情况下您可能更适合使用PuTTY/plink),并确定哪些更改会导致循环重定向。


谢谢您回复。对于循环重定向,我得到了相同的URL返回。但是,如果我在浏览器上输入该URL,则会从服务器收到三个响应,具有相同的URL。第一个是302 Moved temporarily,第二个是302 Found,第三个是200 OK,具有相同的URL……而我想获取此URL的内容。 - arsenal
我已经更新了我的答案,并提出了一些诊断问题的建议。 - Adam Batkin
我在我的Firefox浏览器中使用Firebug。因此,在Firebug中,当我查看响应时,我会看到302 Found、302 Moved temporarily,最后是200 OK的相同URL。 - arsenal
我认为你应该尝试查看所有的头信息,而不仅仅是响应代码,并找出Firefox请求(正常工作)和你的应用程序请求(不正常工作)之间的区别。你可以使用类似于“telnet”的工具来混合和匹配请求的头信息。 - Adam Batkin

2

自4.0版本以来,Apache HttpClient存在一个会导致循环重定向的错误,即使在最新版本中也没有修复。

在DefaultRequestDirector.java文件中,它创建了一个HttpRedirect来执行重定向,并且将重用您原始的HttpGet中的所有标头,问题在于它还将重用Host标头,这意味着服务器仍将获得尝试重定向到新URI后的原始主机。

我通过重新实现DefaultRequestDirector来修复了这个问题:

public class RedirectRequestDirector extends DefaultRequestDirector
{
    RedirectRequestDirector(
            final HttpRequestExecutor requestExec,
            final ClientConnectionManager conman,
            final ConnectionReuseStrategy reustrat,
            final ConnectionKeepAliveStrategy kastrat,
            final HttpRoutePlanner rouplan,
            final HttpProcessor httpProcessor,
            final HttpRequestRetryHandler retryHandler,
            final RedirectHandler redirectHandler,
            final AuthenticationHandler targetAuthHandler,
            final AuthenticationHandler proxyAuthHandler,
            final UserTokenHandler userTokenHandler,
            final HttpParams params) 
    {
        super(requestExec, conman, reustrat, kastrat, rouplan, httpProcessor, retryHandler, redirectHandler, targetAuthHandler, proxyAuthHandler, userTokenHandler, params);

    }
    @Override
    protected RoutedRequest handleResponse(RoutedRequest roureq,
            HttpResponse response,
            HttpContext context)
                    throws HttpException, IOException
    {
        RoutedRequest req = super.handleResponse(roureq, response, context);
        if(req != null)
        {
            String redirectTarget = req.getRoute().getTargetHost().getHostName();
            req.getRequest().getOriginal().setHeader("Host", redirectTarget);
        }
        return req;
    }

}

和DefaultHttpClient:

public class RedirectHttpClient extends DefaultHttpClient
{
    @Override
    protected RequestDirector createClientRequestDirector(
            final HttpRequestExecutor requestExec,
            final ClientConnectionManager conman,
            final ConnectionReuseStrategy reustrat,
            final ConnectionKeepAliveStrategy kastrat,
            final HttpRoutePlanner rouplan,
            final HttpProcessor httpProcessor,
            final HttpRequestRetryHandler retryHandler,
            final RedirectHandler redirectHandler,
            final AuthenticationHandler targetAuthHandler,
            final AuthenticationHandler proxyAuthHandler,
            final UserTokenHandler stateHandler,
            final HttpParams params) {
        return new RedirectRequestDirector(
                requestExec,
                conman,
                reustrat,
                kastrat,
                rouplan,
                httpProcessor,
                retryHandler,
                redirectHandler,
                targetAuthHandler,
                proxyAuthHandler,
                stateHandler,
                params);
    }
}

现在我不会抱怨循环重定向了。

0

在发送到您请求的URL之前,请检查您的请求是否被发送到代理。


0
我在升级Spring版本时遇到了这个问题,我的情况下上下文没有正确初始化。
org.apache.http.impl.client.DefaultRedirectStrategy中:
RedirectLocations redirectLocations = (RedirectLocations) clientContext.getAttribute(
                HttpClientContext.REDIRECT_LOCATIONS);

clientContext 的值应该是 basicHttpContext,但 Spring Web (4.3.x.RELEASE) 正在以下位置初始化上下文:

org.springframework.http.client.HttpComponentsClientHttpRequest.executeInternal();

clientContext的值正在改变,这导致循环重定向错误。 Spring Web(3.2.x.RELEASE)不会初始化上下文,因此该值将为null。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接