spring-projects / spring-framework

Spring Framework
https://spring.io/projects/spring-framework
Apache License 2.0
55.3k stars 37.62k forks source link

HTTP cache and conditional requests support in RestTemplate [SPR-5821] #10491

Closed spring-projects-issues closed 4 years ago

spring-projects-issues commented 14 years ago

Oliver Drotbohm opened SPR-5821 and commented

The main goal is to create a CachingClientHttpRequestInterceptor which provides the following:

This could be used like this:

RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(Collections.singletonList(new CachingClientHttpRequestInterceptor()));

// this response is cacheable and has appropriate headers
ResponseEntity<Book> response = restTemplate.getForEntity("http://example.org/resource", Book.class);
// it is now cached
String etag = response.getHeaders().getEtag();

// if the response is still fresh, then no network call should happen and the response should be reused
Book book = restTemplate.getForObject("http://example.org/resource", Book.class);

Affects: 3.0 M3

Attachments:

Issue Links:

10 votes, 15 watchers

spring-projects-issues commented 14 years ago

Oliver Drotbohm commented

Would like to attach an implemented version but seems I don't have permission to do so.

spring-projects-issues commented 14 years ago

Arjen Poutsma commented

After reading through the Caching chapter in HTTP: The Definitive Guide (highly recommended, btw), this seems a bit more complex than I initially thought. If we want to do caching the right way, then we need to adhere to Cache-Control, Pragma, and Expiry headers, etc.

I'm rescheduling this feature for 3.1.

spring-projects-issues commented 14 years ago

Arjen Poutsma commented

Attaching Oliver's original EtagCachingRestTemplate and the alternative CachingHttpRequestFactory, sent to me via email.

spring-projects-issues commented 13 years ago

Marc Weinberger commented

Are there any plans to provide an extension point for cache providers like ehcache? In an distributed RESTful service environment a solid caching feature for RestTemplate would be great.

spring-projects-issues commented 13 years ago

Arjen Poutsma commented

@Marc, you can certainly use the high-level cache abstraction for that, see #11967.

spring-projects-issues commented 13 years ago

Marc Weinberger commented

Thanks Arjen,

11967 looks very promising. I'll look into it, once the high level cache API is available.

spring-projects-issues commented 13 years ago

Arjen Poutsma commented

Postponing till after 3.1.

spring-projects-issues commented 11 years ago

Michel Zanini commented

This will be good to be included in Android Rest Template also because ETag support is very useful on a mobile environment.

spring-projects-issues commented 9 years ago

Oliver Drotbohm commented

After a recent team discussion we decided to slightly shift the scope of this ticket. Caching is not the right word for what we're trying to achieve here. The core idea is to use the headers sent by the server in response to an original request in subsequent requests to the very same resource. Thus it's rather using HTTP means to optimize the request (using If-None-Match, If-Modified-Since) depending on what the server indicates to understand.

spring-projects-issues commented 8 years ago

Brian Clozel commented

I've given this some thoughts after our discussion and found several problems with that approach.

Leaky design

So with that approach, we'd like to remain at the request/response level and let the framework generate conditional requests for us. Something (very imperfect) like this:

String requestUrl = "http://example.org/users/12"

ResponseEntity<User> cachedResponse = cache.get(requestUrl, User.class);
if(cachedResponse == null) {

  ResponseEntity<User> response = restTemplate.getForEntity(requestUrl, User.class);
  cache.put(requestUrl, response);
}
else {
  ConditionalRequest<User> cRequest = cachedResponse.conditional(restTemplate);
  User user;
  if(cRequest.checkNotModified()) { // issue a conditional GET request and returns true if 304
    user = cRequest.getCachedResponse().getBody();
  }
  else {
    user = cRequest.getResponse().getBody();
    cache.put("http://example.org/users/12", cRequest.getResponse());
  }
}        

This API can be improved in many ways, but I think that leaving the abstraction at that level means we'd need to:

Not simplifying things

This approach generates conditional requests (with proper Etag or If- headers), but leave to the user the following problems:

As soon as we're trying to tackle one of those issues, we're beginning to implement a client http cache.

Implementing a client http cache

Many frameworks/libraries went down that path with more or less complete or elegant implementations. And I'm wondering if there would be interest in this for Spring Framework given that:

  1. even with a great implementation, we'd probably miss some part of the spec or some specific browser/server quirks. It looks like this is the kind of feature that is driven by endless issues and feature requests that can contradict each others.
  2. Spring's HTTP client does not belong to a separate module which make it harder to reuse in other contexts. Such a feature is probably more useful if the http client is somehow standalone
  3. a lot of applications probably implement very simple, ad-hoc clients with @Cacheable annotations for their own use case (like this one

Jakub Jirutka implemented a RequestInterceptor for this - see his project. Some parts can be improved, like conditional requests support and cache keys generation (currently the cache key is the URL itself and does not take into account HTTP headers such as Vary, or encoding...). But it's still in a good shape IMO.

I've sketched something based on Jakub's work and I'm trying to find ways to come up with clean interfaces that would allow custom strategies for caching, conditional requests, etc. But I'm still struggling with the 3 points listed above.

Actually Jakub Jirutka, what do you think about those points? Can you share your experience and tell us why you created this project in the first place and how it's being used?

bclozel commented 4 years ago

In the meantime, RestTemplate has been put in maintenance mode, so we don't intend to invest more there.