Как получить ответ WRO с http 304 без изменений?
Мы предоставляем ресурсы javascript (и другие) через wro в нашем веб-приложении. В среде PROD браузер получает (например) содержимое углового веб-приложения app.js с заголовками "expires" через год.
Это означает, что для последующих запросов браузер извлекает его из кэша без запроса к серверу. Если мы развернем новую версию веб-приложения, браузер не получит новую версию, так как он берет ее из локального кэша.
Цель состоит в том, чтобы сконфигурировать wro или / и spring, чтобы заголовки были правильно установлены, чтобы браузер каждый раз выполнял запрос, а сервер возвращал 304 без изменений. Таким образом, клиенты будут автоматически "обновлять" новое развертывание. Кто-то уже достиг этого?
Мы используем конфигурацию Java Spring:
@Configuration
public class Wro4jConfiguration {
@Value("${app.webapp.web.minimize}")
private String minimize;
@Value("${app.webapp.web.disableCache}")
private String disableCache;
@Autowired
private Environment env;
@Bean(name = "wroFilter")
public WroFilter wroFilter() {
ConfigurableWroFilter filter = new ConfigurableWroFilter();
filter.setWroManagerFactory(new Wro4jManagerFactory());
filter.setWroConfigurationFactory(createProperties());
return filter;
}
private PropertyWroConfigurationFactory createProperties() {
Properties props = new Properties();
props.setProperty("jmxEnabled", "false");
props.setProperty("debug", String.valueOf(!env.acceptsProfiles(EnvConstants.PROD)));
props.setProperty("gzipResources", "false");
props.setProperty("ignoreMissingResources", "true");
props.setProperty("minimizeEnabled", minimize);
props.setProperty("resourceWatcherUpdatePeriod", "0");
props.setProperty("modelUpdatePeriod", "0");
props.setProperty("cacheGzippedContent", "false");
// let's see if server-side cache is disabled (DEV only)
if (Boolean.valueOf(disableCache)) {
props.setProperty("resourceWatcherUpdatePeriod", "1");
props.setProperty("modelUpdatePeriod", "5");
}
return new PropertyWroConfigurationFactory(props);
}
}
2 ответа
Основываясь на информации и справочной информации Алекса, я переопределил WroFilter.setResponseHeaders для установки соответствующих значений expire. Это работает нормально. Wro уже позаботился о настройке ETag, Date и других, поэтому я перезаписываю только задержку истечения и дату.
@Configuration
public class Wro4jConfiguration {
@Value("${app.webapp.web.browserCache.maxAgeInHours}")
private String maxAgeInHours;
@Bean(name = "wroFilter")
public WroFilter wroFilter() {
ConfigurableWroFilter filter = createFilter();
filter.setWroManagerFactory(new Wro4jManagerFactory());
filter.setWroConfigurationFactory(createProperties());
return filter;
}
private ConfigurableWroFilter createFilter() {
return new ConfigurableWroFilter() {
private final int BROWSER_CACHE_HOURS = Integer.parseInt(maxAgeInHours);
private final int BROWSER_CACHE_SECONDS = BROWSER_CACHE_HOURS * 60 * 60;
@Override
protected void setResponseHeaders(final HttpServletResponse response){
super.setResponseHeaders(response);
if (!getConfiguration().isDebug()) {
ZonedDateTime cacheExpires = ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("GMT")).plusHours(BROWSER_CACHE_HOURS);
String cacheExpiresStr = cacheExpires.format(DateTimeFormatter.RFC_1123_DATE_TIME);
response.setHeader(HttpHeader.EXPIRES.toString(), cacheExpiresStr);
response.setHeader(HttpHeader.CACHE_CONTROL.toString(), "public, max-age=" + BROWSER_CACHE_SECONDS);
}
}
};
}
// Other config methods
}
По умолчанию WroFilter устанавливает следующие заголовки: ETag (контрольная сумма md5 ресурса), Cache-Control (public, max-age = 315360000), Expires (1 год с момента создания ресурса).
Есть много деталей о значении этих заголовков. Краткое объяснение таково:
Когда сервер считывает ETag из запроса клиента, сервер может определить, следует ли отправить файл (HTTP 200) или сказать клиенту, чтобы он просто использовал свою локальную копию (HTTP 304). ETag - это просто контрольная сумма для файла, который семантически изменяется при изменении содержимого файла. Если отправляется только ETag, клиент всегда должен будет сделать запрос.
Заголовки Expires и Cache-Control очень похожи и используются клиентом (и прокси-серверами / кэшами), чтобы определить, нужно ли ему вообще отправлять запрос серверу.
Поэтому на самом деле вы хотите использовать ОБА заголовки - установите для заголовка Expires разумное значение, основанное на частоте изменения содержимого. Затем настройте отправку ETag так, чтобы, когда клиенты отправляли запрос на сервер, он мог легче определить, следует ли отправлять файл обратно.
Если вы хотите, чтобы клиент всегда проверял наличие последней версии ресурса, не следует отправлять заголовки expires и control-cache.
В качестве альтернативы, существует более агрессивный метод кэширования: закодируйте контрольную сумму ресурса в его путь. В результате при каждом изменении ресурса путь к этому ресурсу изменяется. Такой подход гарантирует, что клиент всегда будет запрашивать самую последнюю версию. Для этого подхода теоретически ресурсы никогда не должны истекать, так как контрольная сумма изменяется каждый раз, когда ресурс изменяется.