One issue I've had a couple of times now, is handling redirects that are more complicated than the basic "resend the same request to the new location".
I was making a request to one system, which required an Authorization header. This system then redirected me to a file on Amazon S3.
There's a problem with this - Amazon S3 also uses an "Authorization" header, and it was attempting to read my header, rejecting and giving me a 400 Bad Request.
So how do we solves this and the general problem - how can we modify a request in the event of a redirect?
One option is to disable the automatic following of redirects and do all redirecting manually - but this is a lot of work, and it's so easy to have HttpClient handle the redirects for us.
Instead, HttpClient has a RedirectStrategy interface, whose implementing class DefaultRedirectStrategy is executed on every redirect. So, all that is needed, is to create and enable our own RedirectStrategy which strips out the Authorization header if the request is for S3.
To save time and effort, it's easier to just extended DefaultRedirectStrategy:
public class AmazonRedirectStrategy extends DefaultRedirectStrategy {
@Override
public HttpUriRequest getRedirect(HttpRequest request, HttpResponse response, HttpContext context) throws ProtocolException {
Header[] locationHeaders = response.getHeaders("Location");
if (locationHeaders.length >= 1) {
if (locationHeaders[0].getValue().contains("s3.amazonaws.com")) {
((RequestWrapper)request).getOriginal().removeHeaders("Authorization");
}
}
return super.getRedirect(request, response, context);
}
}
You have to cast the original request into a RequestWrapper which according to the JavaDoc is:
"A wrapper class for HttpRequests that can be used to change properties of the current request without modifying the original object."
Then, you need to register this class with your HttpClient. With the latest version, you set this on the HttpClientBuilder whilst you're building the client. If you're using the older < 4.3 DefaultHttpClient, you can set this directly.
That's it! Using this method, you can handle a lot of custom redirect needs without having to perform all the redirecting manually.
I hope someone finds this useful, any questions, errors etc, please leave in the comments.
Will