Sto cercando di passare dal passaggio da Apache CXF RS a JAX RS a Spring MVC REST e vedere alcuni problemi con il modo in cui Spring MVC REST sta gestendo attualmente gli ETags. Forse non sto capendo bene o c'è un modo migliore per realizzare ciò che viene attualmente fatto con JAX RS?Gestione ETag in Spring MVC REST
Utilizzando Apache CXF RS, le condizioni per l'ultimo timestamp modificato e l'ETag vengono valutate all'interno del servizio REST (la valutazione delle condizioni è in realtà piuttosto complicata, vedere le sezioni 14.24 e 14.26 di RFC 2616, quindi sono contento che ciò sia fatto per me). Il codice simile a questa:
@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();
}
Il mio tentativo della stessa cosa con Spring MVC REST sembra qualcosa di simile:
@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!
}
sono d'accordo con la necessità di costruire tutti i dati per una risposta completa in anticipo , anche se non richiesto. Ciò rende l'ETag come usato in Spring MVC REST molto meno prezioso di quanto potrebbe essere. L'idea di un ETag debole per la mia comprensione è che potrebbe essere "economico" costruire il suo valore e confrontarlo. Nel caso felice questo impedisce il carico sul server. Nel caso in cui la risorsa sia stata modificata, la risposta completa deve essere costruita, ovviamente.
Mi sembra che per progettazione Spring MVC REST richieda attualmente la compilazione dei dati completi di risposta, non importa se un corpo per la risposta è in definitiva necessario o meno.
Così, in sintesi due domande per Spring MVC RIPOSO:
- Esiste un equivalente a evaluatePreconditions()?
- Esiste un modo migliore per costruire stringhe ETag?
Grazie per i vostri pensieri!
Buona domanda. Suppongo che se Spring non lo fornisce, puoi estendere 'ResponseEntity' per eseguire un callback per costruire l'intero corpo. – Augusto
Sembra che sia necessario precaricare 'result' in entrambi i casi ... Ma capisco, nel primo caso, è necessario solo qualcosa di economico (ad esempio un numero di versione) per calcolare ETag. La risposta migliore credo sia quella di fare il body building pigro. – ZhongYu
in ultima analisi, in alcune applicazioni, per prestazioni ottimali, l'applicazione deve verificare le condizioni da sola. Questo non è * così * difficile. [Questo] (https://github.com/zhong-j-yu/bayou/blob/0.9/src/bayou/http/ImplRespMod.java#L516) è la mia implementazione della logica, basata sulle discussioni delle ultime specifiche HTTP . – ZhongYu