Я рассматриваю переход от переключения с Apache CXF RS с JAX RS на Spring MVC REST и некоторые проблемы с тем, как Spring MVC REST в настоящее время обрабатывает ETags. Может быть, я не понимаю права или есть лучший способ достичь того, что в настоящее время делается с JAX RS?
Используя Apache CXF RS, условия для последней измененной метки времени и ETag оцениваются внутри службы REST (оценка состояния на самом деле довольно сложная, см. Разделы 14.24 и 14.26 RFC 2616, поэтому я счастлив, что это сделано для меня). Код выглядит примерно так:
@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();
}
Моя попытка сделать то же самое с Spring MVC REST выглядит примерно так:
@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!
}
Я принимаю решение о том, что нужно заранее собрать все данные для полного ответа, даже если это не требуется. Это делает ETag используемым в Spring MVC REST гораздо менее ценным, чем это могло бы быть. Идея слабого ETag для моего понимания заключается в том, что это может быть "дешево", чтобы построить свою ценность и сравнить ее. В счастливом случае это предотвращает загрузку на сервер. В этом случае ресурс был изменен, конечно, полный ответ должен быть построен.
Мне кажется, что по дизайну Spring MVC REST в настоящее время требует, чтобы все данные ответа были построены, независимо от того, требуется ли в конечном итоге тело для ответа.
Итак, в общем, два вопроса для Spring MVC REST:
- Существует ли эквивалент для
evaluatePreconditions()?
- Есть ли лучший способ построения строк ETag?
Спасибо за ваши мысли!