groot sarchy
groot sarchy

Reputation: 110

How do I get the http status message from responses on java.net.HttpClient requests

Some http servers produce responses with a status code and a custom status message. When using the java HttpURLConnection class to make requests this message can be accessed. However, with the more recent java.net.HttpClient style api I can't seem to find a way to access the message itself. I can only find a way to get the status code.

To illustrate the situation, consider the following code:

/**
 * Stand in replacement for a server which puts a custom message in the http status.
 * Blindly sends a fixed http response on every connection in receives, irrespective
 * of protocol or context.
 */
public class ExampleServer {

    private static final int port = 8080;
    private static final byte [] fixed_response = String.join ("\n",
        "HTTP/1.1 403 Missing X-Api-Key header",
        "Content-Length: 12",
        "",
        "Unauthorized"
    ).getBytes(StandardCharsets.UTF_8);

    public static void main (String [] args) throws Exception {
        ServerSocket server = new ServerSocket (port);
        ExecutorService executor = Executors.newCachedThreadPool ();
        while ( true ) {
            Socket socket = server.accept ();
            executor.submit (() -> {
                socket.getOutputStream ().write (fixed_response);
                socket.close ();
                return null;
            });
        }
    }

}

We can show the status with the HttpURLConnection approach.

URI uri = URI.create ("http://localhost:" + port + "/any/path");
HttpURLConnection connection = (HttpURLConnection) uri.toURL ().openConnection ();
connection.setRequestMethod ("GET");

System.out.println ("status: " + connection.getResponseCode () + " " + connection.getResponseMessage ());
System.out.println ("body  : " + new String (connection.getErrorStream ().readAllBytes ()));

How would I create the same output in the following scenario?

HttpClient client = HttpClient.newHttpClient ();
HttpRequest request = HttpRequest.newBuilder ()
    .uri (URI.create ("http://localhost:" + port + "/any/path"))
    .GET ().build ();
HttpResponse<String> response = client.send (request, HttpResponse.BodyHandlers.ofString ());

System.out.println ("status: " + response.statusCode () + " " /* what goes here? */);
System.out.println ("body  : " + response.body ());

Upvotes: 3

Views: 3880

Answers (3)

Marcos Adriano
Marcos Adriano

Reputation: 99

If you using spring you can use HttpStatus from org.springframework.http.HttpStatus like this:

HttpStatus.valueOf(connection.getResponseCode()).getReasonPhrase()

Upvotes: 1

mattmess1221
mattmess1221

Reputation: 4454

As Julian says, the reason doesn't exist anymore in HTTP/2. Although, if you really need to get the name of a given status code, you can use a Map to match numbers to names.

Here is a Map of codes to reasons using the names from MDN.

import java.util.Map;

import static java.util.Map.entry;

public class HttpStatusReasons {

    private static final String UNKNOWN_STATUS = "Unknown Status";

    private static final Map<Integer, String> REASONS = Map.ofEntries(
            // informational
            entry(100, "Continue"),
            entry(101, "Switching Protocol"),
            entry(102, "Processing"),
            entry(103, "Early Hints"),

            // successful
            entry(200, "OK"),
            entry(201, "Created"),
            entry(202, "Accepted"),
            entry(203, "Non-Authoritative Information"),
            entry(204, "No Content"),
            entry(205, "Reset Content"),
            entry(206, "Partial Content"),
            entry(207, "Multi Status"),
            entry(208, "Already Reported"),
            entry(226, "IM Used"),

            // redirection
            entry(300, "Multiple Choice"),
            entry(301, "Moved Permanently"),
            entry(302, "Found"),
            entry(303, "See Other"),
            entry(304, "Not Modified"),
            entry(305, "Use Proxy"), // deprecated
            entry(307, "Temporary Redirect"),
            entry(308, "Permanent Redirect"),

            // client error
            entry(400, "Bad Request"),
            entry(401, "Unauthorized"),
            entry(402, "Payment Required"),
            entry(403, "Forbidden"),
            entry(404, "Not Found"),
            entry(405, "Method Not Allowed"),
            entry(406, "Not Acceptable"),
            entry(407, "Proxy Authentication Required"),
            entry(408, "Request Timeout"),
            entry(409, "Conflict"),
            entry(410, "Gone"),
            entry(411, "Length Required"),
            entry(412, "Precondition Failed"),
            entry(413, "Payload Too Long"),
            entry(414, "URI Too Long"),
            entry(415, "Unsupported Media Type"),
            entry(416, "Range Not Satisfiable"),
            entry(417, "Expectation Failed"),
            entry(418, "I'm a Teapot"),
            entry(421, "Misdirected Request"),
            entry(422, "Unprocessable Entity"),
            entry(423, "Locked"),
            entry(424, "Failed Dependency"),
            entry(425, "Too Early"),
            entry(426, "Upgrade Required"),
            entry(428, "Precondition Required"),
            entry(429, "Too Many Requests"),
            entry(431, "Request Header Fields Too Large"),
            entry(451, "Unavailable for Legal Reasons"),

            // server error
            entry(500, "Internal Server Error"),
            entry(501, "Not Implemented"),
            entry(502, "Bad Gateway"),
            entry(503, "Service Unavailable"),
            entry(504, "Gateway Timeout"),
            entry(505, "HTTP Version Not Supported"),
            entry(506, "Variant Also Negotiates"),
            entry(507, "Insufficient Storage"),
            entry(508, "Loop Detected"),
            entry(510, "Not Extended"),
            entry(511, "Network Authentication Required")
    );

    public static String getReasonForStatus(int status) {
        return REASONS.getOrDefault(status, UNKNOWN_STATUS);
    }
}

Upvotes: 1

Julian Reschke
Julian Reschke

Reputation: 42065

The "reason phrase" really doesn't matter, and doesn't exist anymore in HTTP/2 and HTTP/3. I wouldn't put too much effort in this.

Upvotes: 3

Related Questions