首頁  >  文章  >  web前端  >  使用node解讀http快取的內容

使用node解讀http快取的內容

不言
不言轉載
2018-10-29 14:48:251697瀏覽

這篇文章帶給大家的內容是關於使用node解讀http快取的內容,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

用node搞web服務跟直接用tomcat、Apache做伺服器不太一樣, 很多工作都需要自己做。快取策略也要自己選擇,雖然有像koa-static,express.static這些東西可以用來管理靜態資源,但是為了開發或配置時更加得心應手,知其所以然,有了解http快取的必要。另外,http快取作為一個前端優化的一個重點,也應該有所了解。

什麼是http快取

RFC 7234 (https://tools.ietf.org/pdf/rfc7234.pdf)指出HTTP快取是回應訊息的本地存儲,並且是控制其中訊息的儲存、檢索和刪除的子系統。

通俗講: http協定規定了一些指令, 實作http協定的伺服器和瀏覽器根據這些指令決定要不要以及如何把回應儲存起來以備後續使用.

http快取的意義

提高回應速度

減少頻寬佔用, 省流量

減少伺服器壓力

#不指定任何與快取相關的指令

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

強制快取

所謂強制快取就是給出資源的到期時間expires或有效時間max-age, 在這個時間之內該資源應該被快取.

如何讓一個資源被強緩存

1.expires

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

使用node解讀http快取的內容

可以看到這個expires是個GMT#可以看到這個expires

是個

GMT

時間, 它的工作機制是, 首次請求時, 伺服器在回應中加上

expires標識資源的到期時間, 瀏覽器快取這個資源, 再次請求時, 瀏覽器將上一次請求到這個資源的過期時間與自己的系統時間比較, 若係統時間小於過期時間, 則證明資源沒有過期, 直接用上次快取的資源, 不必請求; 否則重新請求, 伺服器在回應中給予新的過期時間.

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
  • 存在的問題是他依賴客戶端的系統時間, 客戶端系統時間錯誤可能會引起判斷錯誤. HTTP1.1增加了

    Cache-Control解決此問題, 這個指令值比較豐富, 常見的如下:

    public/private:  識別資源能不能被代理伺服器快取,
  • public
  • 識別資源既能被代理伺服器快取也能被瀏覽器快取,

    private

    標識資源只能被瀏覽器快取, 不能被代理伺服器快取.
  • max-age: 用於指定在客戶端快取的有效時間, 單位s, 超過n秒需要重新請求, 不超過則可以使用快取
  • s-maxage: 這個是針對代理伺服器的, 表示資源在代理伺服器快取時間沒有超過這個時間不必向來源伺服器請求, 否則需要.
  • no-cache: 有這個指令表示不走瀏覽器快取了, 協商快取還可以走

    no-store: 強制無快取,協商快取也不走了, 測試發下即使回應中有
  • Last-Modified
, 瀏覽器請求時頁不會帶

If-Modified-Since

使用node解讀http快取的內容一個實例

# 協商快取

所謂協商快取就是客戶端想用快取資源時先向伺服器詢問, 如果伺服器如果認為這個資源沒有過期, 可以繼續用則給出304回應, 客戶端繼續使用原來的資源; 否則給出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無資料, 瀏覽器使用上一次快取的資源.### ###2.Etag與If-None-Match###

Last-Modified模式存两个问题, 一是它是秒级别的比对, 所以当资源的变化小于一秒时浏览器可能使用错误的资源; 二是资源的最新修改时间变了可能内容并没有变, 但是还是会给出完整响应, 造成浪费. 基于此在HTTP1.1引入了Etag模式.

这个与上面的Last-Modified机制基本相同, 不过不再是比对最后修改时间而是比对资源的标识, 这个Etag一般是基于资源内容生成的标识. 由于Etag是基于内容生成的, 所以当且仅当内容变化才会给出完整响应, 无浪费和错误的问题.

演示第8, 10

如何选择缓存策略

https://tools.ietf.org/pdf/rfc7234.pdf

附录

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. 不给任何与缓存相关的头, 任何情况下, 既不会被浏览器缓存, 也不会被代理服务缓存
        case '/img/nothing_1':
            res.writeHead(200, {
                'Content-Type': 'image/png'
            });
            res.end(img);
            break;
            
        // 2. 设置了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. 设置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. 设置了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;

        // 设置了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. 协商缓存
        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 <p>2.测试用代理服务器nginx配置</p><p>不要问我这是个啥, 我是copy的</p><pre class="brush:php;toolbar:false">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;
    #跟后端服务器连接的超时时间_发起握手等候响应超时时间
    proxy_read_timeout 600;
    #连接成功后_等候后端服务器响应的时间_其实已经进入后端的排队之中等候处理
    proxy_send_timeout 500;
    #后端服务器数据回传时间_就是在规定时间内后端服务器必须传完所有数据
    proxy_buffer_size 128k;
    #代理请求缓存区_这个缓存区间会保存用户的头信息以供Nginx进行规则处理_一般只要能保存下头信息即可  
    proxy_buffers 4 128k;
    #同上 告诉Nginx保存单个用的几个Buffer最大用多大空间
    proxy_busy_buffers_size 256k;
    #如果系统很忙的时候可以申请更大的proxy_buffers 官方推荐*2
    proxy_temp_file_write_size 128k;
    #设置web缓存区名为cache_one,内存缓存空间大小为12000M,自动清除超过15天没有被访问过的缓存数据,硬盘缓存空间大小200g
    #要想开启nginx的缓存功能,需要添加此处的两行内容!
    #设置Web缓存区名称为cache_one,内存缓存空间大小为500M,缓存的数据超过1天没有被访问就自动清除;访问的缓存数据,硬盘缓存空间大小为30G
    proxy_cache_path /usr/local/nginx/proxy_cache_path levels=1:2 keys_zone=cache_one:500m inactive=1d max_size=30g;
 
    #创建缓存的时候可能生成一些临时文件存放的位置
    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必须于上一步配置的缓存区域名称相同
            proxy_cache_valid 200 304 12h;
            proxy_cache_valid 301 302 1d;
            proxy_cache_valid any 1h;
            #不同的请求设置不同的缓存时效
            proxy_cache_key $uri$is_args$args;
            #生产缓存文件的key,通过4个string变量结合生成
            expires off;
            #加了这个的话会自己修改cache-control, 写成off则不会
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

以上是使用node解讀http快取的內容的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除