2015-06-14 51 views
2

我們正在通過我們的web應用程序提供javascript資源(和其他)。 在PROD環境中,瀏覽器將在未來一年內獲得(例如)app.js angular webapp的內容,其中包含'expires'標頭。如何讓WRO回答一個未被修改的http 304?

這意味着對於後續請求,瀏覽器將其從緩存中取出而不需要請求到服務器。 如果我們部署新版本的webapp,瀏覽器不會獲得新版本,因爲它會從本地緩存中獲取。

目標是配置wro或/和spring,以便正確設置標題以使瀏覽器每次執行請求,並且服務器返回304未修改。所以我們會讓客戶自動「更新」新的部署。 有人已經做到了嗎?

我們使用Spring的Java配置:

@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); 
} 
} 

回答

1

根據Alex的信息和文檔參考,我最終覆蓋了WroFilter.setResponseHeaders以提供適當的過期值。 這工作正常。 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 

} 
0

默認情況下,WroFilter設置以下標題:ETag的(資源的MD5校驗),緩存控制(公共,最大年齡= 315360000 ),到期(資源創建後1年)。

有關於這些標題的意義的plenty of details。簡短的解釋是這樣的:

當服務器從客戶端請求中讀取ETag時,服務器可以確定是發送文件(HTTP 200)還是告訴客戶端只使用他們的本地副本(HTTP 304)。一個ETag基本上只是一個文件的校驗和,當文件內容發生變化時,它會在語義上發生變化。如果只發送ETag,客戶端將不得不提出請求。

Expires和Cache-Control標頭非常相似,客戶端(和代理/緩存)使用它們來確定它是否甚至需要向服務器發出請求。

所以你真正想要做的是使用BOTH頭文件 - 根據內容更改的頻率將Expires頭文件設置爲一個合理的值。然後配置要發送的ETags,以便當客戶端向服務器發送請求時,可以更容易地確定是否發回文件。

如果您希望客戶端始終檢查最新的資源版本,則不應發送緩存控制標頭過期&。

另外,還有一種更積極的緩存技術:將資源的校驗和編碼到其路徑中。因此,每次資源更改時,該資源的路徑都會更改。這種方法保證了客戶端總是會請求最新的版本。對於這種方法,理論上資源不應該過期,因爲每次資源發生變化時校驗和都會發生變化。

相關問題