一、
開發環境
客戶端:安卓+webview(vuejs)
服務器端:tomcat 8.0
二、問題
使用安卓原生+web(基於webpack+vuejs)的方式開發了一個安卓應用,由於web的js文件較大,大概有400k左右,每次從app中打開該頁面都要重新從服務器端下載頁面的html、js和圖片等靜態資源,反應速度比較慢了,大概需要三四秒(如果用戶網速慢的話,則需要更久),體驗效果就很不好。
所以就考慮是不是可以只在第一次打開的時候下載,然后就緩存在客戶端,以后只有有更新的時候才下載,但是開發人員在將安卓的webview的緩存選項設置為
LOAD_DEFAULT之后,並且在html的head加上如下meta標簽,但是似乎沒有效果,有時候會緩存,有時候有重新下載,和預期的行為不一致。
<meta http-equiv="Cache-Control" content="max-age=
604800
"/>
三、分析
首先
安卓的webview的緩存選項設置為
LOAD_DEFAULT應該沒錯,這點沒有太大疑問,我們就是想要
根據cache-control決定是否從網絡上取數據。
然后重點就是在html中的這個Cache-Control設置,分析之后發現這其實是一個http協議范疇的內容,下圖是《http 權威指南》中的描述。

所以現在要驗證這個在html的cache-control meta標簽是否起作用,可以從兩個方面來找原因:
(1) 首先可以看看tomcat是否支持,比如他在遇到html的時候,是否會解析其中的cache-control meta設置,然后在回復的http報文頭上加上Cache-Control,使用wireshark抓取的html頁面響應的報文頭如下,這說明tomcat默認是不支持解析html頁面頭上的cache-control meta標簽的。

(2) 然后就是看安卓的webview是否支持解析該meta標簽了,這點在android官方的webview說明中沒有招到,可能要去webkit的官方去找。
但是一篇博文上招到如下說明:
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /><meta http-equiv="Pragma" content="no-cache" /><meta http-equiv="Expires" content="0" />
但,實際情況是,這些meta只能在file:// 本地文件中使用,如果是服務器則默認被覆蓋。現在目前主流的就是使用HTTP1.1協議緩存
不過我們一般都不會單獨使用某一項。
所以我估計這個meta tag在android的webview中 是沒有作用的。
四、解決方案
在后端代碼中添加了過濾器,然后回復的http報文頭上就有cache-control,就可以按照設置的max-age正確緩存了。
Filter的代碼:
web.xml里的巧妙配置:
- public class ResponseHeaderFilter implements Filter {
- FilterConfig fc;
- public void doFilter(ServletRequest req, ServletResponse res,
- FilterChain chain) throws IOException, ServletException {
- HttpServletResponse response = (HttpServletResponse) res;
- // set the provided HTTP response parameters
- for (Enumeration e = fc.getInitParameterNames(); e.hasMoreElements();) {
- String headerName = (String) e.nextElement();
- response.addHeader(headerName, fc.getInitParameter(headerName));
- }
- // pass the request/response on
- chain.doFilter(req, response);
- }
- public void init(FilterConfig filterConfig) {
- this.fc = filterConfig;
- }
- public void destroy() {
- this.fc = null;
- }
- }
web.xml里的巧妙配置:
- <filter>
- <filter-name>NoCache</filter-name>
- <filter-class>apis.server.common.util.ResponseHeaderFilter</filter-class>
- <init-param>
- <param-name>Cache-Control</param-name>
- <param-value>no-cache, must-revalidate</param-value>
- </init-param>
- </filter>
- <filter>
- <filter-name>CacheForWeek</filter-name>
- <filter-class>apis.server.common.util.ResponseHeaderFilter</filter-class>
- <init-param>
- <param-name>Cache-Control</param-name>
- <param-value>max-age=604800, public</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>NoCache</filter-name>
- <url-pattern>*.do</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>CacheForWeek</filter-name>
- <url-pattern>/images/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>CacheForWeek</filter-name>
- <url-pattern>/img/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>CacheForWeek</filter-name>
- <url-pattern>/icons/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>CacheForWeek</filter-name>
- <url-pattern>/ext/*</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>CacheForWeek</filter-name>
- <url-pattern>*.js</url-pattern>
- </filter-mapping>
- <filter-mapping>
- <filter-name>CacheForWeek</filter-name>
- <url-pattern>*.css</url-pattern>
- </filter-mapping>
0)親,你知道緩存是什么嗎?
https://segmentfault.com/a/1190000004486640