切換語言為:簡體

Java 如何確保 JavaScript 檔案(或任何靜態資源)不被瀏覽器快取

  • 爱糖宝
  • 2024-10-21
  • 2037
  • 0
  • 0

1. 先來看幾個問題

1. 檔案更新後無法及時生效

瀏覽器快取機制是爲了加快載入速度和減少伺服器壓力,但有時會帶來問題。當 JavaScript 檔案更新後,如果瀏覽器從快取中載入舊版本,使用者就無法看到最新的功能或修復的 Bug。舉個例子:開發者釋出了新版本的前端程式碼,修復了一個關鍵問題,但使用者的瀏覽器仍然使用快取的舊程式碼,導致問題依然存在。使用者可能以為網站沒修復或出現新問題,從而影響使用者體驗。

2. 前後端不一致

在 Java Web 應用中,JavaScript 通常用於與後端服務互動。如果 JavaScript 程式碼版本和後端邏輯不一致,可能導致不相容問題。舉個例子:後端介面的請求格式發生變化,但瀏覽器仍然使用舊的 JavaScript 程式碼,結果是客戶端與伺服器之間通訊失敗,產生錯誤。

3. 影響除錯與開發

在開發和除錯環境中,快取會導致程式碼變更後無法即時看到效果,這對於除錯過程非常不便。開發者可能會在除錯中發現修改的程式碼沒有被應用,導致浪費時間。舉個例子:開發者修改了 JavaScript 檔案,但由於快取,瀏覽器繼續執行舊的程式碼,開發者無法驗證新程式碼是否正確,甚至可能以為程式碼本身有問題。

4. 安全問題

舊的快取可能會暴露系統之前存在的漏洞。即使後端做了升級,修復了安全漏洞,但如果瀏覽器載入了舊的 JavaScript 檔案,可能仍然會受到攻擊。舉個例子:假設某個版本的 JavaScript 中存在一個 XSS 漏洞。雖然新版本已經修復了這個漏洞,但瀏覽器快取的舊檔案仍然暴露在攻擊風險中。

所以,如果前端頁面無法及時響應更新(如修復 Bug、最佳化功能等),使用者體驗可能會受到負面影響。特別是在進行產品版本迭代時,快取問題可能會使新功能看起來未上線,影響使用者的使用體驗和滿意度。

2. 那要如何解決呢?

在 Java Web 開發中,爲了確保 JavaScript 檔案(或任何靜態資源)不被瀏覽器快取,可以使用以下幾種經驗:

1. 使用版本號或時間戳

為 JavaScript 檔案的 URL 新增一個版本號或時間戳,使得每次檔案更新後 URL 不同,這樣瀏覽器會認為是新的資源,從而重新載入。比如:

<script src="app.js?v=1.0.1"></script>

或者使用動態的時間戳:

<script src="app.js?t=<%= System.currentTimeMillis() %>"></script>

透過這種方式,每次生成不同的查詢引數,瀏覽器會認為這是一個新的檔案,不會從快取中讀取。

2. 設定 HTTP 響應頭

在 Java 後端(比如 Spring Boot 或 Servlet),可以透過設定 HTTP 頭來控制快取。常見的 HTTP 頭包括:

  • Cache-Control: 控制快取行為。

  • Pragma: 控制快取行為(主要用於相容 HTTP/1.0)。

  • Expires: 設定資源過期的時間。

示例程式碼(Spring Boot 過濾器):

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class NoCacheFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
        
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
        httpResponse.setHeader("Pragma", "no-cache");
        httpResponse.setHeader("Expires", "0");
        
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void destroy() {}
}

3. 配置靜態資源的快取策略

在 Spring Boot 專案中,可以透過配置類來定義靜態資源的快取策略。例如:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/js/**")
                .addResourceLocations("classpath:/static/js/")
                .setCachePeriod(0); // 0 表示不快取
    }
}

透過 setCachePeriod(0) 設定快取週期為 0,強制瀏覽器每次都從伺服器獲取最新的 JavaScript 檔案。

4. 使用 ETagLast-Modified

在 HTTP 響應中設定 ETagLast-Modified,這樣瀏覽器在每次請求時都會詢問伺服器資源是否更新。如果沒有變化,伺服器會返回 304 狀態碼,從而避免不必要的重新載入。

示例(設定 Last-Modified):

httpResponse.setDateHeader("Last-Modified", System.currentTimeMillis());

上面的幾種方法,能確保瀏覽器及時獲取最新版本的 JavaScript 檔案,不使用快取的舊版本。

關於一些思考

問題來了,那什麼時候可以使用快取?

雖然快取可能帶來這些問題,但並不意味著快取永遠不好。在某些場景中,使用瀏覽器快取可以顯著提升效能:

  • 靜態資源(如 JavaScript、CSS 檔案)較少更改時,快取可以顯著減少網路請求,提升頁面載入速度。

  • 確保在更新時有效控制快取機制(比如用檔案的版本號或雜湊值作為檔名的一部分)可以避免不必要的重新下載和過度載入。

如何平衡?

通常,咱們不會完全禁止快取,而是透過版本號、雜湊、快取控制頭等方式來平衡效能和更新問題。這樣,瀏覽器在沒有必要時可以利用快取,而在需要時也能獲取最新的資源。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.