Spring Framework
  1. Spring Framework
  2. SPR-7911

Better handling of 204 No Content in RestTemplate

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 3.1 M1
    • Fix Version/s: 3.1 RC1
    • Component/s: Web
    • Labels:
      None
    • Last commented by a User:
      false

      Description

      Some REST web services return 204 No Content as the result for a GET in certain circumstances. With this status, the response has no entity body and thus no Content-Type header.

      RestTemplate.getForEntity throws an exception when receiving such a response:

      org.springframework.web.client.RestClientException: Cannot extract response: no Content-Type found

      An improvement for RestTemplate.getForEntity would be to return a ResponseEntity instance with the statusCode property set as appropriate for 204 No Content, and null values for the body and contentType properties.

      I considered trying to extend RestTemplate to make it behave in this manner. Unfortunately, the extensive use of private static classes in the implementation makes it difficult to override the behavior of getForEntity – can't just replace the ResponseEntityResponseExtractor implementation without also replacing other unrelated collaborators (e.g. AcceptHeaderRequestCallback). It's possible to do it, it would just require a lot more code duplication than really seems warranted.

      If you don't wish to change the behavior of RestTemplate.getForEntity, perhaps you might consider relaxing the access modifiers on these collaborator classes so that a subclass could make use of them?

        Activity

        Hide
        Juan Antonio Farré Basurte added a comment -

        This is not only important for 204 responses, but also for others, like 304.

        In fact, I consider 304 more important, as 204 responses can be predicted in advance (I don't personally see why a get should return 204 and not other status like 404, but I don't doubt that there may be services out there returning 204 for get requests). But 304 can be returned (obviously without an entity) in a get request that (conditionally) expects an entity body, and this should be handled somehow. A generic exception doesn't allow to recognize this situation.

        My own hack to workaround this, is to have a response error handler that raises a HttpStatusCodeException including response headers. getForEntity catches it and returns an ResponseEntity with the corresponding status code, response headers, and a null body. This would be nicer if there wouldn't need to be an exception involved.

        Other possibility would be just to raise an exception, but one that allows you to discriminate the situation.

        Many cases should be taken into account about responses without an entity, depending on whether:

        • It is a status code that never has a response body or one that can have it.
        • This response could generally be expected (for example a no-content delete response can generally be expected and the client shouldn't specify an expected body, unless he knows that service will send content for that delete query), or it cannot be known in advance (for example a 304 response to a conditional get).
        • The response must include an entity and no entity was detected (for example, a status 200 for a get request without a response entity). This I think should behave as it does now, as it is an illegal response.
        • There is a response entity, but the status code indicates that probably the entity is not what was initially expected (for example, for 3xx responses to a get request that have a response entity, probably the entity is not what the client was expecting for a 200 response and won't probably deserialize correctly to the given response class).
        • Other possible considerations.

        I don't know what should exactly be done in each case, but I think it's worth considering all this carefully to provide a coherent behavior of the rest template in all possible situations.

        Show
        Juan Antonio Farré Basurte added a comment - This is not only important for 204 responses, but also for others, like 304. In fact, I consider 304 more important, as 204 responses can be predicted in advance (I don't personally see why a get should return 204 and not other status like 404, but I don't doubt that there may be services out there returning 204 for get requests). But 304 can be returned (obviously without an entity) in a get request that (conditionally) expects an entity body, and this should be handled somehow. A generic exception doesn't allow to recognize this situation. My own hack to workaround this, is to have a response error handler that raises a HttpStatusCodeException including response headers. getForEntity catches it and returns an ResponseEntity with the corresponding status code, response headers, and a null body. This would be nicer if there wouldn't need to be an exception involved. Other possibility would be just to raise an exception, but one that allows you to discriminate the situation. Many cases should be taken into account about responses without an entity, depending on whether: It is a status code that never has a response body or one that can have it. This response could generally be expected (for example a no-content delete response can generally be expected and the client shouldn't specify an expected body, unless he knows that service will send content for that delete query), or it cannot be known in advance (for example a 304 response to a conditional get). The response must include an entity and no entity was detected (for example, a status 200 for a get request without a response entity). This I think should behave as it does now, as it is an illegal response. There is a response entity, but the status code indicates that probably the entity is not what was initially expected (for example, for 3xx responses to a get request that have a response entity, probably the entity is not what the client was expecting for a 200 response and won't probably deserialize correctly to the given response class). Other possible considerations. I don't know what should exactly be done in each case, but I think it's worth considering all this carefully to provide a coherent behavior of the rest template in all possible situations.
        Hide
        Roy Clarkson added a comment -

        User's of Spring Android are also experiencing issues with 204 responses:

        http://forum.springsource.org/showthread.php?103806-Small-issue-with-http-204

        Show
        Roy Clarkson added a comment - User's of Spring Android are also experiencing issues with 204 responses: http://forum.springsource.org/showthread.php?103806-Small-issue-with-http-204
        Hide
        Arjen Poutsma added a comment -

        Fixed by introducing a hasMessageBody(ClientHttpResponse) method in HttpMessageConverterExtractor, which defaults to checking for 204, 304 and a Content-Length of 0.

        Show
        Arjen Poutsma added a comment - Fixed by introducing a hasMessageBody(ClientHttpResponse) method in HttpMessageConverterExtractor, which defaults to checking for 204, 304 and a Content-Length of 0.
        Hide
        Roy Clarkson added a comment -

        This change was merged into Spring for Android and released in 1.0.0.RC1.

        See ANDROID-57.

        Show
        Roy Clarkson added a comment - This change was merged into Spring for Android and released in 1.0.0.RC1. See ANDROID-57 .

          People

          • Assignee:
            Arjen Poutsma
            Reporter:
            Carl Harris
            Last updater:
            Trevor Marshall
          • Votes:
            1 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:
              Days since last comment:
              2 years, 4 weeks ago

              Time Tracking

              Estimated:
              Original Estimate - Not Specified
              Not Specified
              Remaining:
              Remaining Estimate - 0d
              0d
              Logged:
              Time Spent - 19m
              19m