处理 HttpClient 重定向

Posted

技术标签:

【中文标题】处理 HttpClient 重定向【英文标题】:Handling HttpClient Redirects 【发布时间】:2011-03-02 15:12:07 【问题描述】:

我正在将一些数据发布到响应 302 Moved Temporarily 的服务器。

我希望 HttpClient 遵循重定向并自动获取新位置,因为我相信这是 HttpClient 的默认行为。但是,我遇到了一个异常并且没有遵循重定向:(

这是相关的代码,任何想法将不胜感激:

HttpParams httpParams = new BasicHttpParams();
HttpClientParams.setRedirecting(httpParams, true);
SchemeRegistry schemeRegistry = registerFactories();
ClientConnectionManager clientConnectionManager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);

HttpClient httpClient = new DefaultHttpClient(clientConnectionManager, httpParams)
HttpPost postRequest = new HttpPost(url);
postRequest.setHeader(HTTP.CONTENT_TYPE, contentType);
postRequest.setHeader(ACCEPT, contentType);

if (requestBodyString != null) 
    postRequest.setEntity(new StringEntity(requestBodyString));


return httpClient.execute(postRequest, responseHandler);

【问题讨论】:

你遇到了什么异常? 异常是HttpResponseException 【参考方案1】:

对于 HttpClient 4.3

HttpClient instance = HttpClientBuilder.create()
                     .setRedirectStrategy(new LaxRedirectStrategy()).build();

对于 HttpClient 4.2

DefaultHttpClient client = new DefaultHttpClient();
client.setRedirectStrategy(new LaxRedirectStrategy());

对于 HttpClient

DefaultHttpClient client = new DefaultHttpClient();
client.setRedirectStrategy(new DefaultRedirectStrategy() 
    /** Redirectable methods. */
    private String[] REDIRECT_METHODS = new String[]  
        HttpGet.METHOD_NAME, HttpPost.METHOD_NAME, HttpHead.METHOD_NAME 
    ;

    @Override
    protected boolean isRedirectable(String method) 
        for (String m : REDIRECT_METHODS) 
            if (m.equalsIgnoreCase(method)) 
                return true;
            
        
        return false;
    
);

【讨论】:

谢谢!想知道他们流畅的 api 是否可以做到这一点? 我希望 HttpClient 在重定向后使用其表单数据重播我的原始 POST 请求,但是,发出了 HTTP GET 请求。我知道这是规范,但对我来说没用:( 如果您使用RequestConfig,在构建配置时可以使用两种方法:setRedirectsEnabledsetRelativeRedirectsAllowed,像这样使用:org.apache.http.client.config.RequestConfig reqCfg = RequestConfig.copy(RequestConfig.DEFAULT).setRedirectsEnabled(true).setRelativeRedirectsAllowed(true).build();,然后像这样使用它:@987654328 @【参考方案2】:

HttpClient 的默认行为符合 HTTP 规范 (RFC 2616) 的要求

10.3.3 302 找到 ... 如果收到 302 状态代码以响应其他请求 与 GET 或 HEAD 相比,用户代理不能自动重定向 请求,除非它可以被用户确认,因为这可能 更改发出请求的条件。

您可以通过继承 DefaultRedirectStrategy 并覆盖其#isRedirected() 方法来覆盖 HttpClient 的默认行为。

【讨论】:

我已经覆盖了 DefaultRedirectHandler 的 #isRedirectRequested() 以考虑 POST 方法并且它按预期工作。谢谢! 如何使用 httpPost 并覆盖 DefaultRedirectHandler 的 #isRedirectRequested() ? 302 行为在RFC 7231 中重新定义:“用户代理可以使用位置字段值进行自动重定向。”【参考方案3】:

默认情况下似乎禁用了 http 重定向。我尝试启用,它可以工作,但我的问题仍然存在错误。但是我们仍然可以务实地处理重定向。我认为你的问题可以解决: 这么老的代码:

androidHttpClient httpClient = AndroidHttpClient.newInstance("User-Agent");
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpGet);
long contentSize = httpResponse.getEntity().getContentLength();

如果发生 http 重定向,此代码将返回 contentSize = -1

然后我在尝试启用默认跟随重定向后自己处理重定向

AndroidHttpClient client;
HttpGet httpGet;
HttpResponse response;
HttpHeader httpHeader;
private void handleHTTPRedirect(String url) throws IOException 
    if (client != null)
        client.close();

    client = AndroidHttpClient.newInstance("User-Agent");
    httpGet = new HttpGet(Network.encodeUrl(url));
    response = client.execute(httpGet);
    httpHeader = response.getHeaders("Location");
    while (httpHeader.length > 0) 
        client.close();
        client = AndroidHttpClient.newInstance("User-Agent");

        httpGet = new HttpGet(Network.encodeUrl(httpHeader[0].getValue()));
        response = client.execute(httpGet);
        httpHeader = response.getHeaders("Location");
    

使用中

handleHTTPRedirect(url);
long contentSize = httpResponse.getEntity().getContentLength();

谢谢 阮

【讨论】:

只是提示,您可能应该限制重定向计数,这种方法可能*导致 ANR,因为恶意或编程不当的内容会不断重定向。【参考方案4】:

我的解决方案是使用 HttClient。我不得不将响应发回给调用者。这是我的解决方案

    CloseableHttpClient httpClient = HttpClients.custom()
            .setRedirectStrategy(new LaxRedirectStrategy())
            .build();

    //this reads the input stream from POST
    ServletInputStream str = request.getInputStream();

    HttpPost httpPost = new HttpPost(path);
    HttpEntity postParams = new InputStreamEntity(str);
    httpPost.setEntity(postParams);

    HttpResponse httpResponse = null ;
    int responseCode = -1 ;
    StringBuffer response  = new StringBuffer();

    try 

        httpResponse = httpClient.execute(httpPost);

        responseCode = httpResponse.getStatusLine().getStatusCode();
        logger.info("POST Response Status::   for file   ", responseCode, request.getQueryString());

        //return httpResponse ;
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                httpResponse.getEntity().getContent()));

        String inputLine;
        while ((inputLine = reader.readLine()) != null) 
            response.append(inputLine);
        
        reader.close();

        logger.info(" Final Complete Response   " + response.toString());
        httpClient.close();

     catch (Exception e) 

        logger.error("Exception ", e);

     finally 

        IOUtils.closeQuietly(httpClient);

    

    // Return the response back to caller
    return  new ResponseEntity<String>(response.toString(), HttpStatus.ACCEPTED);

【讨论】:

以上是关于处理 HttpClient 重定向的主要内容,如果未能解决你的问题,请参考以下文章

C# HttpClient 不处理 304/307 重定向

apach的httpclient怎么处理重定向请求?cookie信息怎么设置?session怎么保持?

java爬虫知识盲区整理

深入理解HttpClient

httpclient 中post请求重定向

Httpclient 4,错误 302。如何重定向?