成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

用node探究下http緩存

CODING / 3357人閱讀

摘要:用探究下緩存用搞服務和直接用做服務器不太一樣,很多工作都需要自己做。另外,緩存作為一個前端優(yōu)化的一個要點,也應該有所了解。什么是緩存指出緩存是響應消息的本地存儲,并且是控制其中消息的存儲檢索和刪除的子系統(tǒng)。

用node探究下http緩存
用node搞web服務和直接用tomcat、Apache做服務器不太一樣, 很多工作都需要自己做。緩存策略也要自己選擇,雖然有像koa-static,express.static這些東西可以用來管理靜態(tài)資源,但是為了開發(fā)或配置時更加得心應手,知其所以然,有了解http緩存的必要。另外,http緩存作為一個前端優(yōu)化的一個要點,也應該有所了解。
什么是http緩存

RFC 7234 (https://tools.ietf.org/pdf/rfc7234.pdf)指出HTTP緩存是響應消息的本地存儲,并且是控制其中消息的存儲、檢索和刪除的子系統(tǒng)。

通俗講: http協(xié)議規(guī)定了一些指令, 實現(xiàn)http協(xié)議的服務器和瀏覽器根據(jù)這些指令決定要不要以及如何把響應存儲起來以備后續(xù)使用.

http緩存的意義

提高響應速度

減少帶寬占用, 省流量

減小服務器壓力

不指定任何與緩存有關(guān)的指令

這種情況下瀏覽器不做緩存, 每次都會想服務器請求. 但是比較奇怪的是在nginx的實現(xiàn)中, 這種情況下還是被代理服務器做了緩存.也就是說, 當多次請求同一個資源時, 代理服務器只向源服務器請求一次.

演示第1個例子nothing_1

強制緩存

所謂強制緩存就是給出資源的到期時間expires或者有效時間max-age, 在這個時間之內(nèi)該資源應該被緩存.

如何讓一個資源被強緩存

1.expires

這個字段定義了一個資源到期的時間. 看一個實際的例子:

可以看到這個expires是個GMT時間, 它的工作機制是, 首次請求時, 服務器在響應中加上expires標識資源的到期時間, 瀏覽器緩存這個資源, 再次請求時, 瀏覽器將上一次請求到這個資源的過期時間與自己的系統(tǒng)時間對比, 若系統(tǒng)時間小于過期時間, 則證明資源沒有過期, 直接用上次緩存的資源, 不必請求; 否則重新請求, 服務器在響應中給出新的過期時間.

演示第9個例子expires_9

const d  = new Date(Date.now() + 5000);
res.writeHead(200, {
    "Content-Type": "image/png",
    "expires": d.toGMTString()
});
res.end(img);

2.Cache-Control:[public | private,] max-age=${n}, s-maxage=${m}

expires 存在的問題是他依賴于客戶端的系統(tǒng)時間, 客戶端系統(tǒng)時間錯誤可能會引起判斷錯誤. HTTP1.1增加了Cache-Control解決此問題, 這個指令值比較豐富, 常見的如下:

public/private: 標識資源能不能被代理服務器緩存, public 標識資源既能被代理服務器緩存也能被瀏覽器緩存, private標識資源只能被瀏覽器緩存, 不能被代理服務器緩存.

max-age: 用于指定在客戶端緩存的有效時間, 單位s, 超過n秒需要重新請求, 不超過則可以使用緩存

s-maxage: 這個是針對代理服務器的, 表示資源在代理服務器緩存時間沒有超過這個時間不必向源服務器請求, 否則需要.

no-cache: 有這個指令表示不走瀏覽器緩存了, 協(xié)商緩存還可以走

no-store: 強制無緩存, 協(xié)商緩存也不走了, 測試發(fā)下即使響應中有Last-Modified, 瀏覽器請求時頁不會帶If-Modified-Since

一個實例

演示第2,3,4,5,7

協(xié)商緩存

所謂協(xié)商緩存就是客戶端想用緩存資源時先向服務器詢問, 如果服務器如果認為這個資源沒有過期, 可以繼續(xù)用則給出304響應, 客戶端繼續(xù)使用原來的資源; 否則給出200, 并在響應body加上資源, 客戶端使新的資源.

1.Last-Modified與If-Modified-Since

這個機制是, 服務器在響應頭中加上Last-Modified, 一般是一個資源的最后修改時間, 瀏覽器首次請求時獲得這個時間, 下一次請求時將這個時間放在請求頭的If-Modified-Since, 服務器收到這個If-Modified-Since時間n后查詢資源的最后修改時間m與之對比, 若m>n, 給出200響應, 更新Last-Modified為新的值, body中為這個資源, 瀏覽器收到后使用新的資源; 否則給出304響應, body無數(shù)據(jù), 瀏覽器使用上一次緩存的資源.

2.Etag與If-None-Match

Last-Modified模式存兩個問題, 一是它是秒級別的比對, 所以當資源的變化小于一秒時瀏覽器可能使用錯誤的資源; 二是資源的最新修改時間變了可能內(nèi)容并沒有變, 但是還是會給出完整響應, 造成浪費. 基于此在HTTP1.1引入了Etag模式.

這個與上面的Last-Modified機制基本相同, 不過不再是比對最后修改時間而是比對資源的標識, 這個Etag一般是基于資源內(nèi)容生成的標識. 由于Etag是基于內(nèi)容生成的, 所以當且僅當內(nèi)容變化才會給出完整響應, 無浪費和錯誤的問題.

演示第8, 10

如何選擇緩存策略

https://developers.google.cn/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-cn

附錄

1.演示代碼

const http = require("http");
const fs = require("fs");
let etag = 0;
let tpl = fs.readFileSync("./index.html");
let img = fs.readFileSync("./test.png");
http.createServer((req, res) => {
    etag++; // 我是個假的eTag
    console.log("--->", req.url);
    switch (req.url) {
        // 模板
        case "/index":
            res.writeHead(200, {
                "Content-Type": "text/html",
                "Cache-Control": "no-store"
            });
            res.end(tpl);
            break;
        // 1. 不給任何與緩存相關(guān)的頭, 任何情況下, 既不會被瀏覽器緩存, 也不會被代理服務緩存
        case "/img/nothing_1":
            res.writeHead(200, {
                "Content-Type": "image/png"
            });
            res.end(img);
            break;
            
        // 2. 設(shè)置了no-cache表明每次要使用緩存資源前需要向服務器確認
        case "/img/cache-control=no-cache_2":
            res.writeHead(200, {
                "Content-Type": "image/png",
                "cache-control": "no-cache"
            });
            res.end(img);
            break;

        // 3. 設(shè)置max-age表示在瀏覽器最多緩存的時間
        case "/img/cache-control=max-age_3":
            res.writeHead(200, {
                "Content-Type": "image/png",
                "cache-control": "max-age=10"
            });
            res.end(img);
            break;

        // 4. 設(shè)置了max-age s-maxage public: public 是說這個資源可以被服務器緩存, 也可以被瀏覽器緩存, 
        // max-age意思是瀏覽器的最長緩存時間為n秒, s-maxage表明代理服務器的最長緩存時間為那么多秒
        case "/img/cache-control=max-age_s-maxage_public_4":
            res.writeHead(200, {
                "Content-Type": "image/png",
                "cache-control": "public, max-age=10, s-maxage=40"
            });
            res.end(img);
            break;

        // 設(shè)置了max-age s-maxage private: private 是說這個資源只能被瀏覽器緩存, 不能被代理服務器緩存
        // max-age說明了在瀏覽器最長緩存時間, 這里的s-maxage實際是無效的, 因為不能被代理服務緩存
        case "/img/cache-control=max-age_s-maxage_private_5":
            res.writeHead(200, {
                "Content-Type": "image/png",
                "cache-control": "private, max-age=10, s-maxage=40"
            });
            res.end(img);
            break;
        
        // 7. 可以被代理服務器緩存, 確不能被瀏覽器緩存
        case "/img/cache-control=private_max-age_7":
            res.writeHead(200, {
                "Content-Type": "image/png",
                "cache-control": "public, s-maxage=40"
            });
            res.end(img);
            break;
        // 8. 協(xié)商緩存
        case "/img/talk_8":
            let stats = fs.statSync("./test.png");
            let mtimeMs = stats.mtimeMs;
            let If_Modified_Since = req.headers["if-modified-since"];
            let oldTime = 0;
            if(If_Modified_Since) {
                const If_Modified_Since_Date = new Date(If_Modified_Since);
                oldTime = If_Modified_Since_Date.getTime();
            }
            
            mtimeMs = Math.floor(mtimeMs / 1000) * 1000;    // 這種方式的精度是秒, 所以毫秒的部分忽略掉
            console.log("mtimeMs", mtimeMs);
            console.log("oldTime", oldTime);
            if(oldTime < mtimeMs) {
                res.writeHead(200, {
                    "Cache-Control": "no-cache",   
                    // 測試發(fā)現(xiàn), 必須要有max-age=0 或者no-cache,或者expires為當前, 才會協(xié)商, 否則沒有協(xié)商的過程 
                    "Last-Modified": new Date(mtimeMs).toGMTString()
                });
                res.end(fs.readFileSync("./test.png"));
            }else {
                res.writeHead(304);
                res.end();
            }
           
        // 9. 設(shè)置了expires, 表示資源到期時間
        case "/img/expires_9":
            const d  = new Date(Date.now() + 5000);
            res.writeHead(200, {
                "Content-Type": "image/png",
                "expires": d.toGMTString()
            });
            res.end(img);
            break;
        
        // 10. 設(shè)置了expires, 表示資源到期時間
        case "/img/etag_10":
            const If_None_Match = req.headers["if-none-match"];
            console.log("If_None_Match,",If_None_Match);
            if(If_None_Match != etag) {
                res.writeHead(200, {
                    "Content-Type": "image/png",
                    "Etag": String(etag)
                });
                res.end(img);
            }else {
                res.statusCode = 304;
                res.end();
            }
            
            break;

        // 11. no-store 能協(xié)商緩存嗎? 不能, 請求不會帶if-modified-since
        case "/img/no-store_11":
            const stats2 = fs.statSync("./test.png");
            let mtimeMs2 = stats2.mtimeMs;
            let If_Modified_Since2 = req.headers["if-modified-since"];
            let oldTime2 = 0;
            if(If_Modified_Since2) {
                const If_Modified_Since_Date = new Date(If_Modified_Since2);
                oldTime2 = If_Modified_Since_Date.getTime();
            }
            
            mtimeMs2 = Math.floor(mtimeMs2 / 1000) * 1000;    // 這種方式的精度是秒, 所以毫秒的部分忽略掉
            console.log("mtimeMs", mtimeMs2);
            console.log("oldTime", oldTime2);
            if(oldTime2 < mtimeMs2) {
                res.writeHead(200, {
                    "Cache-Control": "no-store",   
                    // 測試發(fā)現(xiàn), 必須要有max-age=0 或者no-cache,或者expires為當前, 才會協(xié)商, 否則沒有協(xié)商的過程 
                    "Last-Modified": new Date(mtimeMs2).toGMTString()
                });
                res.end(fs.readFileSync("./test.png"));
            }else {
                res.writeHead(304);
                res.end();
            }
        default:
            res.statusCode = 404;
            res.statusMessage = "Not found",
            res.end();
    }

}).listen(1234);

2.測試用代理服務器nginx配置

不要問我這是個啥, 我是copy的

worker_processes  8;
  
events {
    worker_connections  65535;
}
  
http {
    include       mime.types;
    default_type  application/octet-stream;
    charset utf-8;
 
    log_format  main  "$http_x_forwarded_for $remote_addr $remote_user [$time_local] "$request" "
                      "$status $body_bytes_sent "$http_referer" "
                      ""$http_user_agent" "$http_cookie" $host $request_time";
    sendfile       on;
    tcp_nopush     on;
    tcp_nodelay    on;
    keepalive_timeout  65;
    proxy_connect_timeout 500;
    #跟后端服務器連接的超時時間_發(fā)起握手等候響應超時時間
    proxy_read_timeout 600;
    #連接成功后_等候后端服務器響應的時間_其實已經(jīng)進入后端的排隊之中等候處理
    proxy_send_timeout 500;
    #后端服務器數(shù)據(jù)回傳時間_就是在規(guī)定時間內(nèi)后端服務器必須傳完所有數(shù)據(jù)
    proxy_buffer_size 128k;
    #代理請求緩存區(qū)_這個緩存區(qū)間會保存用戶的頭信息以供Nginx進行規(guī)則處理_一般只要能保存下頭信息即可  
    proxy_buffers 4 128k;
    #同上 告訴Nginx保存單個用的幾個Buffer最大用多大空間
    proxy_busy_buffers_size 256k;
    #如果系統(tǒng)很忙的時候可以申請更大的proxy_buffers 官方推薦*2
    proxy_temp_file_write_size 128k;
    #設(shè)置web緩存區(qū)名為cache_one,內(nèi)存緩存空間大小為12000M,自動清除超過15天沒有被訪問過的緩存數(shù)據(jù),硬盤緩存空間大小200g
    #要想開啟nginx的緩存功能,需要添加此處的兩行內(nèi)容!
    #設(shè)置Web緩存區(qū)名稱為cache_one,內(nèi)存緩存空間大小為500M,緩存的數(shù)據(jù)超過1天沒有被訪問就自動清除;訪問的緩存數(shù)據(jù),硬盤緩存空間大小為30G
    proxy_cache_path /usr/local/nginx/proxy_cache_path levels=1:2 keys_zone=cache_one:500m inactive=1d max_size=30g;
 
    #創(chuàng)建緩存的時候可能生成一些臨時文件存放的位置
    proxy_temp_path /usr/local/nginx/proxy_temp_path;
 
    fastcgi_connect_timeout 3000;
    fastcgi_send_timeout 3000;
    fastcgi_read_timeout 3000;
    fastcgi_buffer_size 256k;
    fastcgi_buffers 8 256k;
    fastcgi_busy_buffers_size 256k;
    fastcgi_temp_file_write_size 256k;
    fastcgi_intercept_errors on;
  
     
    client_header_timeout 600s;
    client_body_timeout 600s;
  
    client_max_body_size 100m;             
    client_body_buffer_size 256k;           
  
    gzip  off;
    gzip_min_length  1k;
    gzip_buffers     4 16k;
    gzip_http_version 1.1;
    gzip_comp_level 9;
    gzip_types       text/plain application/x-javascript text/css application/xml text/javascript;
    gzip_vary on;
  
 
    include vhosts/*.conf;
    server {
        listen       80;
        server_name  localhost;
        location / {
            proxy_pass  http://127.0.0.1:1234;
            proxy_set_header   Host             $http_host;
            proxy_set_header   X-Real-IP        $remote_addr;
            proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_redirect off;
            proxy_cache cache_one;
            #此處的cache_one必須于上一步配置的緩存區(qū)域名稱相同
            proxy_cache_valid 200 304 12h;
            proxy_cache_valid 301 302 1d;
            proxy_cache_valid any 1h;
            #不同的請求設(shè)置不同的緩存時效
            proxy_cache_key $uri$is_args$args;
            #生產(chǎn)緩存文件的key,通過4個string變量結(jié)合生成
            expires off;
            #加了這個的話會自己修改cache-control, 寫成off則不會
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}
參考文獻

https://juejin.im/book/5b936540f265da0a9624b04b/section/5b9ba651f265da0ac726e5de

這是一個付費的冊子,可能沒法訪問

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/98776.html

相關(guān)文章

  • Node.js模塊化機制原理探究

    摘要:要想讓模塊再次運行,必須清除緩存。用戶自己編寫的模塊,稱為文件模塊。并且和指向了同一個模塊對象。模塊路徑這是在定位文件模塊的具體文件時指定的查找策略,具體表現(xiàn)為一個路徑組成的數(shù)組。 前言 Node應用是由模塊組成的,Node遵循了CommonJS的模塊規(guī)范,來隔離每個模塊的作用域,使每個模塊在它自身的命名空間中執(zhí)行。 CommonJS規(guī)范的主要內(nèi)容: 模塊必須通過 module.exp...

    aikin 評論0 收藏0
  • WEB緩存探究第二彈——實戰(zhàn)

    摘要:前言緩存探究第一彈中我們講了一些緩存的基礎(chǔ)知識和策略。第二彈我們來講講如何實際在項目中配置。在緩存探究第一彈定制緩存策略中已經(jīng)提到對于最好標記為不緩存,以便及時獲取最新的靜態(tài)資源版本。 前言 WEB緩存探究第一彈中我們講了一些WEB緩存的基礎(chǔ)知識和策略。第二彈我們來講講如何實際在項目中配置。 實戰(zhàn) 鑒于叉燒包本包是個前端,所以我們就以HTML和Node為例開始showImg(https...

    linkin 評論0 收藏0
  • WEB緩存探究第二彈——實戰(zhàn)

    摘要:前言緩存探究第一彈中我們講了一些緩存的基礎(chǔ)知識和策略。第二彈我們來講講如何實際在項目中配置。在緩存探究第一彈定制緩存策略中已經(jīng)提到對于最好標記為不緩存,以便及時獲取最新的靜態(tài)資源版本。 前言 WEB緩存探究第一彈中我們講了一些WEB緩存的基礎(chǔ)知識和策略。第二彈我們來講講如何實際在項目中配置。 實戰(zhàn) 鑒于叉燒包本包是個前端,所以我們就以HTML和Node為例開始showImg(https...

    孫淑建 評論0 收藏0
  • WEB緩存探究第二彈——實戰(zhàn)

    摘要:前言緩存探究第一彈中我們講了一些緩存的基礎(chǔ)知識和策略。第二彈我們來講講如何實際在項目中配置。在緩存探究第一彈定制緩存策略中已經(jīng)提到對于最好標記為不緩存,以便及時獲取最新的靜態(tài)資源版本。 前言 WEB緩存探究第一彈中我們講了一些WEB緩存的基礎(chǔ)知識和策略。第二彈我們來講講如何實際在項目中配置。 實戰(zhàn) 鑒于叉燒包本包是個前端,所以我們就以HTML和Node為例開始showImg(https...

    waltr 評論0 收藏0
  • WEB緩存探究第二彈——實戰(zhàn)

    摘要:前言緩存探究第一彈中我們講了一些緩存的基礎(chǔ)知識和策略。第二彈我們來講講如何實際在項目中配置。在緩存探究第一彈定制緩存策略中已經(jīng)提到對于最好標記為不緩存,以便及時獲取最新的靜態(tài)資源版本。 前言 WEB緩存探究第一彈中我們講了一些WEB緩存的基礎(chǔ)知識和策略。第二彈我們來講講如何實際在項目中配置。 實戰(zhàn) 鑒于叉燒包本包是個前端,所以我們就以HTML和Node為例開始showImg(https...

    jcc 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<