Search code examples
javahttp-redirectjava-http-client

How to follow-through on HTTP 303 status code when using HttpClient in Java 11 and later?


When using the java.net.http.HttpClient classes in Java 11 and later, how does one tell the client to follow through an HTTP 303 to get to the redirected page?

Here is an example. Wikipedia provides a REST URL for getting the summary of a random page of their content. That URL redirects to the URL of the randomly-chosen page. When running this code, I see the 303 when calling HttpResponse#toString. But I do not know how to tell the client class to follow along to the new URL.

HttpClient client = HttpClient.newHttpClient();
HttpRequest request =
        HttpRequest
                .newBuilder()
                .uri( URI.create( "https://en.wikipedia.org/api/rest_v1/page/random/summary" ) )
                .build();
try
{
    HttpResponse < String > response = client.send( request , HttpResponse.BodyHandlers.ofString() );
    System.out.println( "response = " + response );   // ⬅️ We can see the `303` status code.
    String body = response.body();
    System.out.println( "body = " + body );
}
catch ( IOException e )
{
    e.printStackTrace();
}
catch ( InterruptedException e )
{
    e.printStackTrace();
}

When run:

response = (GET https://en.wikipedia.org/api/rest_v1/page/random/summary) 303

body =


Solution

  • Problem

    You're using HttpClient#newHttpClient(). The documentation of that method states:

    Returns a new HttpClient with default settings.

    Equivalent to newBuilder().build().

    The default settings include: the "GET" request method, a preference of HTTP/2, a redirection policy of NEVER [emphasis added], the default proxy selector, and the default SSL context.

    As emphasized, you are creating an HttpClient with a redirection policy of NEVER.


    Solution

    There are at least two solutions to your problem.

    Automatically Follow Redirects

    If you want to automatically follow redirects then you need to use HttpClient#newBuilder() (instead of #newHttpClient()) which allows you to configure the to-be-built client. Specifically, you need to call HttpClient.Builder#followRedirects(HttpClient.Redirect) with an appropriate redirect policy before building the client. For example:

    HttpClient client = 
        HttpClient.newBuilder()
            .followRedirects(HttpClient.Redirect.NORMAL) // follow redirects
            .build();
    

    The different redirect policies are specified by the HttpClient.Redirect enum:

    Defines the automatic redirection policy.

    The automatic redirection policy is checked whenever a 3XX response code is received. If redirection does not happen automatically, then the response, containing the 3XX response code, is returned, where it can be handled manually.

    There are three constants: ALWAYS, NEVER, and NORMAL. The meaning of the first two is obvious from their names. The last one, NORMAL, behaves just like ALWAYS except it won't redirect from https URLs to http URLs.

    Manually Follow Redirects

    As noted in the documentation of HttpClient.Redirect you could instead manually follow a redirect. I'm not well versed in HTTP and how to properly handle all responses so I won't give an example here. But I believe, at a minimum, this requires you:

    1. Check the status code of the response.
    2. If the code indicates a redirect, grab the new URI from the response headers.
    3. If the new URI is relative then resolve it against the request URI.
    4. Send a new request.
    5. Repeat 1-4 as needed.

    Obviously configuring the HttpClient to automatically follow redirects is much easier (and less error-prone), but this approach would give you more control.