Czekam na przełączenie z przełączania z Apache CXF RS z JAX RS na Spring MVC REST i zobacz niektóre problemy ze sposobem Spring MVC REST aktualnie obsługuje ETags. Może nie rozumiem dobrze, czy jest lepszy sposób na osiągnięcie tego, co obecnie robi JAX RS?Obsługa ETag w Spring MVC REST
Używanie Apache CXF RS, warunki dla ostatniej modyfikacji znacznika czasu i ETag są oceniane wewnątrz usługi REST (ocena stanu jest rzeczywiście dość skomplikowana, patrz RFC 2616, sekcja 14.24 i 14.26, więc cieszę się, że to jest zrobione dla mnie). Kod wygląda mniej więcej tak:
@GET
@Path("...")
@Produces(MediaType.APPLICATION_JSON)
public Response findBy...(..., @Context Request request) {
... result = ...fetch-result-or-parts-of-it...;
final EntityTag eTag = new EntityTag(computeETagValue(result), true);
ResponseBuilder builder = request.evaluatePreconditions(lastModified, eTag);
if (builder == null) {
// a new response is required, because the ETag or time stamp do not match
// ...potentially fetch full result object now, then:
builder = Response.ok(result);
} else {
// a new response is not needed, send "not modified" status without a body
}
final CacheControl cacheControl = new CacheControl();
cacheControl.setPrivate(true); // store in private browser cache of user only
cacheControl.setMaxAge(15); // may stay unchecked in private browser cache for 15s, afterwards revalidation is required
cacheControl.setNoTransform(true); // proxies must not transform the response
return builder
.cacheControl(cacheControl)
.lastModified(lastModified)
.tag(eTag)
.build();
}
Moja próba samo z wiosennym MVC REST wygląda mniej więcej tak:
@RequestMapping(value="...", produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<...> findByGpnPrefixCacheable(...) {
... result = ...fetch-result...;
// ... result = ...fetch-result-or-parts-of-it...; - can't fetch parts, must obtain full result, see below
final String eTag = "W/\""+computeETagValue(result)+"\""; // need to manually construct, as opposed to convenient JAX RS above
return ResponseEntity
.ok() // always say 'ok' (200)?
.cacheControl(
CacheControl
.cachePrivate()
.maxAge(15, TimeUnit.SECONDS)
.noTransform()
)
.eTag(eTag)
.body(result); // ETag comparison takes place outside controller(?), but data for a full response has already been built - that is wasteful!
}
zgadzam się z konieczności tworzenia wszystkich danych do pełnej odpowiedzi wyprzedzeniem , nawet jeśli nie jest to wymagane. To sprawia, że ETag używany w Spring MVC REST jest o wiele mniej wartościowy niż mógłby być. Pomysł słabego ETag do mojego zrozumienia jest taki, że "tanie" może budować swoją wartość i porównywać ją. W szczęśliwym przypadku zapobiega to obciążeniu serwera. W przypadku zmodyfikowania zasobu należy oczywiście zbudować pełną odpowiedź.
Wydaje mi się, że zgodnie z projektem Spring MVC REST wymaga obecnie utworzenia pełnych danych odpowiedzi, bez względu na to, czy jednostka docelowa jest ostatecznie potrzebna, czy nie.
Więc podsumowując dwa pytania Spring MVC rekreacyjne:
- Czy istnieje odpowiednik evaluatePreconditions()?
- Czy istnieje lepszy lepszy sposób konstruowania ciągów ETag?
Dzięki za twoje myśli!
Dobre pytanie. Sądzę, że jeśli Spring nie zapewni tego po wyjęciu z pudełka, można rozszerzyć 'ResponseEntity', aby wykonać wywołanie zwrotne, aby zbudować całe ciało. – Augusto
Wygląda na to, że musisz wczytać "wynik" w obu przypadkach ... Ale rozumiem, że w pierwszym przypadku potrzebujesz tylko taniego (np. Numeru wersji) do obliczenia ETag. Najlepszą odpowiedzią, jak sądzę, jest leniwe budowanie ciała. – ZhongYu
ostatecznie, w niektórych aplikacjach, aby uzyskać najlepszą wydajność, aplikacja musi sam przetestować warunki. To nie jest * to * trudne. [To] (https://github.com/zhong-j-yu/bayou/blob/0.9/src/bayou/http/ImplRespMod.java#L516) jest moją implementacją logiki opartej na dyskusjach najnowszej specyfikacji HTTP . – ZhongYu