Tuesday, September 7, 2010

Redirects handling in httpclient

Problem:
Httpclient cannot get correct response from production server (http://production.domain.com/servlet.do)

Root cause:
In production, http request will be redirected to https by load balancer (302 redirect code). There are a few types of redirect that HttpClient can't handle automatically, including 302, in entity enclosing methods (POST and PUT).

    * 301 Moved Permanently. HttpStatus.SC_MOVED_PERMANENTLY
    * 302 Moved Temporarily. HttpStatus.SC_MOVED_TEMPORARILY
    * 303 See Other. HttpStatus.SC_SEE_OTHER
    * 307 Temporary Redirect. HttpStatus.SC_TEMPORARY_REDIRECT

    * 300 Multiple Choices. HttpStatus.SC_MULTIPLE_CHOICES
    * 304 Not Modified. HttpStatus.SC_NOT_MODIFIED
    * 305 Use Proxy. HttpStatus.SC_USE_PROXY

Solution:
Handling redirects manually in codes for entity enclosing methods.

Sample Code:
    // Create an instance of HttpClient.
    HttpClient client = new HttpClient();
   
    // Create a method instance.
    //HttpMethod method = new GetMethod(url); //good with redirects unless setFollowRedirects(false)
    //method.setFollowRedirects(true);
    PostMethod method = new PostMethod(url); //entity enclosing methods
   
    // Provide custom retry handler is necessary
    method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
            new DefaultHttpMethodRetryHandler(3, false));
    try {
      // Execute the method.
      int statusCode = client.executeMethod(method);
     
      if (statusCode != HttpStatus.SC_OK) {

          Header locationHeader = method.getResponseHeader("location");
          method.releaseConnection();
         
          if (locationHeader != null) {
              System.out.println(locationHeader.getValue());
              method = new PostMethod(locationHeader.getValue());
              statusCode = client.executeMethod(method);
          }
      }

      // Read the response body.
      byte[] responseBody = method.getResponseBody();

      // Deal with the response.
      // Use caution: ensure correct character encoding and is not binary data
      System.out.println(new String(responseBody));

    } catch (HttpException e) {
      System.err.println("Fatal protocol violation: " + e.getMessage());
    } catch (IOException e) {
      System.err.println("Fatal transport error: " + e.getMessage());
    } finally {
      // Release the connection.
      method.releaseConnection();
    } 
Notes:
  1. Http specification defines two entity enclosing methods, POST and PUT.
  2. Redirects is automatically handled by httpclient in GET method, unless setFollowRedirects(false).
Background:
Httpclient is a popular http1.1 compliant agent implementation, open sourced at apache. There are 2 typical versions now, one is legacy commons httpclient (v3.1), and the other is the new HttpComponents (v4.x), successor of and replacement of commons-httpclient.

commons-httpclient-3.1.jar (org.apache.commons.httpclient)
commons-codec-1.4.jar (org.apache.commons.codec)

httpclient-4.0.1.jar (org.apache.http)
httpcore-4.0.1.jar (org.apache.http)

Reference:
http://hc.apache.org/
http://hc.apache.org/httpclient-3.x/redirects.html
http://hc.apache.org/httpcomponents-client-4.0.1/tutorial/html/index.html

No comments:

Post a Comment