Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-7911

Better handling of 204 No Content in RestTemplate

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: 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?

        Issue Links

          Activity

          Hide
          juan.farre 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.farre 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
          rclarkson 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
          rclarkson 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 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 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
          rclarkson Roy Clarkson added a comment -

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

          See ANDROID-57.

          Show
          rclarkson 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 Arjen Poutsma
              Reporter:
              ceharris414 Carl Harris
              Last updater:
              Stéphane Nicoll
            • Votes:
              1 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:
                Days since last comment:
                3 years, 9 weeks, 2 days ago

                Time Tracking

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