Search code examples
javaspring-boothttpresttemplate

Difference between HttpClientErrorException.getStatusText and HttpClientErrorException.getResponseBodyAsString


I use httpResp.sendError(400, "You are missing customer id") to send the response back

When I try to retrieve the message on the client side (using Rest template to call the endpoint).

However, printing the HttpClientErrorException always produces the following result for me:

HttpClientErrorException: 400 null

I see that I have HttpClientErrorException.getResponseBody has all the information about time stamp, message etc. But HttpClientErrorException.getStatusText is always empty.

My question is : How do you design your ResponseEntity on the server-side such that the HTTP client finds the server-side exception message in response.getStatusText() instead of null?

here is the code I have

        try{
        ResponseEntity<String> responseEntity = restTemplate.exchange(uri, HttpMethod.POST, requestEntity, String.class );
        System.out.println(responseEntity.getBody());
    }
    catch (HttpClientErrorException | HttpServerErrorException e) {
        if (e.getStatusCode().equals(HttpStatus.UNAUTHORIZED) || e.getStatusCode().equals(HttpStatus.FORBIDDEN)) {                System.out.println("Response Body returned:");
            System.out.println(e.getResponseBodyAsString());
            System.out.println("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
            System.out.println("Status text is:");
            System.out.println(e.getStatusText());

        } else if (e.getStatusCode().equals(HttpStatus.BAD_REQUEST)) {
            System.out.println("Response Body returned:");
            System.out.println(e.getResponseBodyAsString());
            System.out.println("-------------------------------");
            System.out.println("Status text is:");
            System.out.println(e.getStatusText());
        } else {
                throw e;
        }
    }

Sprint Boot Version: 2.1.0.RELEASE


Solution

  • I traced the code for how RestTemplate actually makes the calls. Basically what happens is the result of HttpClientErrorException.getStatusText() is populated by the HTTP status code's text and not your custom error message. For example, instead of just returning back error code 400, a server might return back error 400 Bad Request. Instead of status code 200, a server might return back 200 OK. If the server responds back with that optional text, that's what you'll see when you call getStatusText(). Note that that text like OK and Bad Request can't be customized by you on the server side.

    This is happening because, internally, Spring is making use of SimpleClientHttpResponse.getStatusText() which is internally relying on HttpUrlConnection.getResponseMessage(). As you can see from getResponseMessage's Javadoc, the possible values returned aren't meant to be custom error messages. Note that in your case, getStatusText() is returning null because your server is just sending back a status line like 400 and not 400 Bad Request. You can also see this from the Javadoc. You can probably configure your server to send back status code text messages, but doing so still won't help you use the getStatusText() method to get your custom error message.

    Consequently, the HttpClientErrorException.getStatusText() just isn't what you need. Instead, you need to continue calling getResponseBodyAsString(). However, if you know the format of the response body that is sent back from the server (since this will likely be wrapped in HTML and other stuff) you can use a regex to filter out the non-useful parts of the response message.