1. 程式人生 > >Nginx靜態資源快取策略配置

Nginx靜態資源快取策略配置

1. 問題-背景

以前也經常用nginx,但用的不深,通常是簡單的設定個location用來做反向代理。直到今天給客戶做專案碰到快取問題:客戶有個app,只是用原生做了個殼,裡面的內容都是用h5寫的,我們半途接手將新版本靜態資源部署到伺服器上後,發現手機端一直顯示老的頁面,一抓包,發現手機端根本就沒有去請求新的html頁面,定位是快取問題。

2. 配置

乍一看,客戶原來的配置好像沒什麼問題,該有的也全有了

# 這是客戶原來的配置
server {
    listen       80 default_server;
    server_name  xxx.xxx.com;
    root         /app/xxx/html/mobile/;

    location ~ .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$
    {
        expires      7d;
    }

    location ~ .*\.(?:js|css)$
    {
        expires      7d;
    }

    location ~ .*\.(?:htm|html)$
    {
        add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
    }

    location ^~/mobile/
    {
        alias /app/xxx/html/mobile/;
    }
}

乍看沒問題,但就是沒有生效,由於查詢nginx文件,發現nginx的location有優先順序之分(是否生效與放置的位置沒有關係)。

2.1 nginx location的四種類別

【=】模式: location = path,此種模式優先順序最高(但要全路徑匹配)  【^~】模式:location ^~ path,此種模式優先順序第二高於正則;  【~ or ~*】模式:location ~ path,正則模式,優先順序第三,【~】正則匹配區分大小寫,【~*】正則匹配不區分大小寫;  【path】模式: location path,中間什麼都不加,直接跟路徑表示式; 注意:一次請求只能匹配一個location,一旦匹配成功後,便不再繼續匹配其餘location;

一對照,發現location ^~優先順序高於那些正則的快取策略,所以快取策略肯定不會對其生效,一翻查詢下,終於解決了,配置如下:

server {
    listen       80 default_server;
    server_name  xxx.xxx.com;
    root         /app/xxx/html/mobile/;

    location ~ .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$
    {
        expires      7d;
    }

    location ~ .*\.(?:js|css)$
    {
        expires      7d;
    }

    location ~ .*\.(?:htm|html)$
    {
        add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
    }

    location ^~/mobile/
    {
        alias /app/xxx/html/mobile/;
    # 將快取策略用if語句寫在location裡面,生效了
        if ($request_filename ~* .*\.(?:htm|html)$)
        {
            add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
        }

        if ($request_filename ~* .*\.(?:js|css)$)
        {
            expires      7d;
        }

        if ($request_filename ~* .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$)
        {
            expires      7d;
        }
    }
}

3. 配置優化

上面的配置雖然解決了快取問題,但一看就發現冗餘程式碼較多,應該不是最佳實踐,於是請教了前公司專業運維同事,優化後的配置如下:

server {
    listen       80 default_server;
    server_name  xxx.xxx.com;
    # 通過此語句來對映靜態資源
    # 查詢客戶最初的配置,發現也有此項,但配置錯誤,後面多加了一個mobile, 解析時目錄變成了/app/xxx/html/mobile/mobile,報404
    # 估計也是因為此處配置錯誤不生效,後面才又加了個location來對映,但location又不能繼承外層的快取策略
    # 估計原來配置此nginx的人也是個半吊子
    root         /app/xxx/html/;

    location ~ .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$
    {
        expires      7d;
    }

    location ~ .*\.(?:js|css)$
    {
        expires      7d;
    }

    location ~ .*\.(?:htm|html)$
    {
        add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
    }
}    

4. 深化

專案通常就是靜態資源與介面,介面一般都很少碰到快取問題(因為很少有人去給介面配置快取策略,不配置的話就不快取),碰到快取問題的通常都是靜態資源。 靜態資源——html:  html檔案最容易碰到快取問題,重新發版後,一旦客戶端繼續使用原來的快取,那麼在原來的快取過期之前,沒有任何辦法去觸使客戶端更新,除非一個個通知android客戶手動清除app快取資料,通知IOS使用者解除安裝重灌。所以配置html快取策略時要格外小心,我們專案是不快取html檔案; 靜態資源——js/css/各種型別的圖片:  此類資源改動較少,為了提升使用者體驗,一般都需要配置快取,但反而不容易碰到快取問題。因為現在的前程工程也都需要build,在build時工具會自動在檔名上加時間戳,這樣一發新版時,只要客戶端請求了新版的html,裡面引用的js/css/jpg等都已經換了路徑,肯定也就不會使用本地的快取了。