51

I'm POSTing some data to a server that is answering a 302 Moved Temporarily.

I want HttpClient to follow the redirect and automatically GET the new location, as I believe it's the default behaviour of HttpClient. However, I'm getting an exception and not following the redirect :(

Here's the relevant piece of code, any ideas will be appreciated:

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);
mgv
  • 8,384
  • 3
  • 43
  • 47

5 Answers5

99

For HttpClient 4.3:

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

For HttpClient 4.2:

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

For HttpClient < 4.2:

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;
    }
});
RTF
  • 6,214
  • 12
  • 64
  • 132
  • 1
    thanks ! Curious to know if this is possible with their fluent api? – redochka May 15 '17 at 07:58
  • 1
    I was hoping that HttpClient will replay my original POST request with its form data when following the redirect, however, a HTTP GET request was made. I know this is the spec but Useless for me :( – redochka May 15 '17 at 09:01
  • 2
    If you use `RequestConfig` there are two methods you can use while building the config: `setRedirectsEnabled` and `setRelativeRedirectsAllowed`, used like this: `org.apache.http.client.config.RequestConfig reqCfg = RequestConfig.copy(RequestConfig.DEFAULT).setRedirectsEnabled(true).setRelativeRedirectsAllowed(true).build();` and then use it like this: `HttpGet get = new HttpGet(someUri); get.setConfig(reqCfg);` – FrustratedWithFormsDesigner May 26 '17 at 21:07
40

The default behaviour of HttpClient is compliant with the requirements of the HTTP specification (RFC 2616)

10.3.3 302 Found
...

   If the 302 status code is received in response to a request other
   than GET or HEAD, the user agent MUST NOT automatically redirect the
   request unless it can be confirmed by the user, since this might
   change the conditions under which the request was issued.

You can override the default behaviour of HttpClient by sub-classing DefaultRedirectStrategy and overriding its #isRedirected() method.

ok2c
  • 26,450
  • 5
  • 63
  • 71
  • 1
    I've overriden #isRedirectRequested() of DefaultRedirectHandler to consider also POST methods and it's working as expected. Thanks! – mgv Mar 02 '11 at 17:52
  • how about using httpPost with e overriden #isRedirectRequested() of DefaultRedirectHandler ? – Jeff Bootsholz Nov 17 '13 at 16:02
  • 302 behavior was redefined in [RFC 7231](https://tools.ietf.org/html/rfc7231#section-6.4.3): _"The user agent MAY use the Location field value for automatic redirection."_ – Helen Aug 03 '20 at 17:21
1

It seem http redirect is disable by default. I try to enable, it work but I'm still got error with my problem. But we still can handle redirection pragmatically. I think your problem can solve: So old code:

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

This code will return contentSize = -1 if http redirect happend

And then I handle redirect by myself after trying enable default follow redirection

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

In use

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

Thanks Nguyen

Khai Nguyen
  • 3,065
  • 1
  • 31
  • 24
  • Just a tip, you should probably limit the redirect count, this approach may* result in a ANR as malicious or poorly programmed content will constantly redirect. – David Mar 30 '16 at 18:51
0

My solution is using HttClient. I had to send the response back to the caller. This is my solution

    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);
vsingh
  • 6,365
  • 3
  • 53
  • 57
0

For HttpClient v5, just use the below:

httpClient = HttpClientBuilder.create()
            .setRedirectStrategy(new DefaultRedirectStrategy() {
                @Override
                public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context)
                        throws ProtocolException {
                    return false;
                }
            }).build();
  • I don't believe this answers the question, as this will disable all redirects. With v5, redirects for all HTTP methods will be followed by default (equivalent to v4's LaxRedirectStrategy). – Lucas Ross May 17 '23 at 05:56