likes
comments
collection
share

Web开发中的强缓存和协商缓存策略(二)

作者站长头像
站长
· 阅读数 28

Web开发中的强缓存和协商缓存策略(二)

一. 相关参数

1. 强缓存

  • Expires

    ExpiresHTTP/1.0中定义的一个响应头字段,它表示资源的过期时间,即在这个时间之前,浏览器可以直接从浏览器缓存中获取资源,而不需要向服务器发送请求。Expires的值是一个GMT格式的时间字符串,例如:

    response.setHeader('Expires',new Date(Date.now()+3600000).toUTCString());
    

    上面代码表示缓存时间设置为1小时,即在1小时之后,浏览器会向服务器发送请求获取最新的资源。

  • Cache-Control

    Cache-ControlHTTP/1.1中新增的缓存控制方式,它可以更加灵活地控制缓存行为。Cache-Control的值可以是多个指令,每个指令之间用逗号分隔,例如:

    response.setHeader('Cache-Control','max-age=3600,public');
    

    上面代码表示缓存设置时间为1小时,并允许其他用户共享缓存。

    指令表示
    max-age指定缓存的最大有效时间,单位为秒
    no-cache表示缓存需要重新验证,即每次都需要向服务器发送请求
    no-store表示禁止缓存,每次都需要向服务器发送请求
    public表示允许其他用户共享缓存
    private表示只允许当前用户使用缓存

综上所述,ExpiresCache-Control都是强缓存的参数,可以通过设置不同的值来控制缓存行为。在实际开发中,建议使用Cache-Control来代替Expires,因为Cache-Control的优先级更高,而且可以更加灵活地控制缓存行为。

2. 协商缓存

  • Last-Modified

    Last-Modified表示资源的最后修改时间,服务器在响应请求时会将该参数返回给客户端。客户端在下一次请求时会将该参数作为If-Modified-Since的值发送给服务器,服务器会比较该值和资源的最后修改时间,如果相同则返回304 Not Modified,否则返回新资源。

    const express = require('express');
    const app = express();
    
    app.get('/api/data', (req, res) => {
        let data = { name: 'Tom', age: 20 };
        let lastModified = new Date('2023-06-08');
    
        if (req.headers['if-modified-since'] === lastModified.toUTCString()) {
            res.status(304).end();
        } else {
            res.set('Last-Modified', lastModified.toUTCString());
            res.json(data);
        }
    })
    
    app.listen(3000, () => {
        console.log('http://127.0.0.1:3000', '端口启动中......');
    })
    
  • ETag

    ETag表示资源的唯一标识符,服务器在响应请求时会将该参数返回给客户端。客户端在下一次请求时会将该参数作为If-None-Match的值发送给服务器,服务器会比较该值和资源的ETag值,如果相同则返回304 Not Modified,否则返回新的资源。

    const express = require('express');
    const app = express();
    
    app.get('/api/data', (req, res) => {
        let data = { name: 'Tom', age: 20 };
        let etag = '123456789';
    
        if (req.header['if-none-match'] === etag) {
            res.status(304).end();
        } else {
            res.set('ETag', etag);
            res.json(data);
        }
    })
    
    app.listen(3000, () => {
        console.log('http://127.0.0.1:3000', '端口启动中......');
    })
    
  • Cache-Control

    Cache-Controle表示缓存控制的指令,可以设置缓存的过期时间、是否允许缓存、是否允许缓存的内容被修改等。常见的指令包括max-age,no-cache,no-store等。

    const express = require('express');
    const app = express();
    
    app.get('/api/data', (req, res) => {
        let data = { name: 'Tom', age: 20 };
    
        res.set('Cache-Control', 'max-age=3600');
        res.json(data);
    })
    
    app.listen(3000, () => {
        console.log('http://127.0.0.1:3000', '端口启动中......');
    })
    
  • Expires

    Expires表示资源的过期时间,服务器在响应请求时会将该参数返回给客户端。客户端在下一次请求时会比较该值和当前时间,如果资源已经过期则发送新的请求,否则使用缓存的资源。

    const express = require('express');
    const app = express();
    
    app.get('/api/data', (req, res) => {
        let data = { name: 'Tom', age: 20 };
        let expires = new Date(Date.now() + 3600000);
    
        res.set('Expires', expires.toISOString());
        res.json(data);
    
    })
    
    app.listen(3000, () => {
        console.log('http://127.0.0.1:3000', '端口启动中......');
    })
    

二. 协商缓存结合axios的实际运用

1. 创建axios实例

首先,我们需要创建一个axios实例,可以通过axios.create()方法来创建。在创建实例时,可以设置一些默认参数,例如请求的基础URL超时时间等。

import axios from 'axios';

const instance = axios.create({
  baseURL: 'https://example.com/api',
  timeout: 5000
});

2. 添加请求拦截器

接下来,我们需要添加一个请求拦截器,在请求头中添加缓存控制参数。这些参数包括Cache-ControlPragmaIf-Modified-SinceIf-None-Match等。这些参数用于告诉服务器我们需要进行缓存控制,并且不需要缓存。

instance.interceptors.request.use(config => {
  config.headers['Cache-Control'] = 'no-cache';
  config.headers['Pragma'] = 'no-cache';
  config.headers['If-Modified-Since'] = '0';
  config.headers['If-None-Match'] = '';
  return config;
}, error => {
  return Promise.reject(error);
});

3. 添加响应拦截器

接下来,我们需要添加一个响应拦截器,在响应头中获取缓存控制参数。这些参数包括Cache-ControlExpiresLast-ModifiedETag等。根据这些参数,我们可以判断是否需要缓存,并且可以将响应数据缓存到本地。

instance.interceptors.response.use(response => {
  const cacheControl = response.headers['cache-control'];
  const expires = response.headers['expires'];
  const lastModified = response.headers['last-modified'];
  const etag = response.headers['etag'];

  // 判断是否需要缓存
  if (cacheControl && cacheControl.includes('no-cache')) {
    return response.data;
  }

  // 判断是否命中缓存
  if (response.status === 304) {
    return localStorage.getItem(response.config.url);
  }

  // 将响应数据缓存到本地
  localStorage.setItem(response.config.url, JSON.stringify(response.data));

  return response.data;
}, error => {
  return Promise.reject(error);
});

4. 发送请求

最后,我们可以使用axios实例来发送请求,例如发送一个GET请求:

instance.get('/data').then(response => {
  console.log(response);
}).catch(error => {
  console.log(error);
});

5. 将代码整合

//引入axios
import axios from 'axios'

//创建axios实例
const instance = axios.create({
    baseURL: 'http://example.com/api',
    timeout: 5000
})

//添加请求拦截器
instance.interceptors.request.use(config => {
    //在请求头中添加缓存控制参数
    config.headers['Cache-Control'] = 'no-cache';
    config.headers['Pragma'] = 'no-cache';
    config.headers['If-Modified-Since'] = '0';
    config.headers['If-None-Match'] = '';
}, error => {
    return Promise.reject(error);
})

//添加响应拦截器
instance.interceptors.response.use(response => {
    //在请求头中获取缓存控制参数
    const cacheControl = response.headers['cache-control'];
    const expires = response.headers['expires'];
    const lastModified = response.headers['last-modified'];
    const etag = response.headers['etag'];

    //判断是否需要缓存
    if (cacheControl && cacheControl.includes('no-cache')) {
        return response.data;
    }

    //判断是否命中缓存
    if (response.status === 304) {
        return localStorage.getItem(response.config.url);
    }

    //将响应数据缓存到本地
    localStorage.setItem(response.config.url, JSON.stringify(response.data));

    return response.data;
}, error => {
    return Promise.reject(error);
})


//发送get请求
instance.get('/data').then(response => {
    console.log(response);
}).catch(error => {
    console.log(error)
})

在请求拦截器中,我们添加了四个请求头参数,分别是Cache-ControlPragmaIf-Modified-SinceIf-None-Match。这些参数用于告诉服务器我们需要进行缓存控制,并且不需要缓存。如果服务器返回的响应头中包含了缓存控制参数,我们就可以根据这些参数来判断是否需要缓存。

在响应拦截器中,我们首先获取了响应头中的缓存控制参数,然后根据这些参数来判断是否需要缓存。如果需要缓存,我们就将响应数据缓存到本地。如果不需要缓存,我们就直接返回响应数据。如果服务器返回的状态码是304,说明命中了缓存,我们就可以从本地缓存中获取数据。

最后,我们发送了一个GET请求,并在控制台中输出了响应数据。开发者可以根据实际情况来修改请求头参数和响应头参数,以实现更加灵活的缓存控制。

转载自:https://juejin.cn/post/7242237897993453627
评论
请登录