Reputation: 110
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
Reputation: 99
If you using spring you can use HttpStatus from org.springframework.http.HttpStatus like this:
HttpStatus.valueOf(connection.getResponseCode()).getReasonPhrase()
Upvotes: 1
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
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