理解cookie、session、localStorage、sessionStorage、Service-Worker

601 阅读9分钟

1. 常用的存储方式

浏览器中的常用的存储方式有以下几种:

存储方式解释
cookie用于存储跨页面的简单数据,可以设置失效时间和作用域。
session用于存储跨页面的简单数据,可以设置失效时间和作用域。
sessionStorage与 localStorage 类似,但仅在当前会话期间有效,关闭标签页或浏览器时数据被清除。
localStorage用于永久性存储关键数据,数据持久有效,如果用户不手动清除数据,就会一直存在
IndexedDB浏览器本地数据库的标准 API,可存储大量、结构化的数据,允许异步事务处理。
Web SQL Database一种轻量级的关系型数据库系统,使用 SQL 语言,可在浏览器中存储结构化、大量的数据。
Cache API一种用于缓存网络请求的API,可以将请求和响应数据存储在浏览器中,以提高网站的性能。
Service Worker一种独立于网页本身的 JavaScript 运行环境,可以拦截网络请求、缓存资源和提供离线支持。

除了上述的存储方式,还有File API、Sync API、Clipboard API、Device Storage API、Web Share API 等其它的存储技术。这些存储方式的使用根据具体的需求和浏览器支持情况而异。

2. 使用

2.1 cookie

class Cookie {
        /** 读取 Cookie */
    getItem(name) {
        const regEx = new RegExp('(^|; )' + name + '=([^;]*)');
        const result = document.cookie.match(regEx)
        console.log('打印***result', result)
        return result ? decodeURIComponent(result[2]) : null
    }
    /** 设置 Cookie */
    setItem(name, value, days) {
        let cookieStr = name + '=' + encodeURIComponent(value)
        if (days) {
                const expires = new Date()
                expires.setTime(expires.getTime() + days)// *864e5 天数
                cookieStr += ';expires=' + expires.toUTCString()
        }
        document.cookie = cookieStr
    }
    /** 删除 Cookie */
    removeItem(name) {
        const expires = new Date(0)
        document.cookie = name + '=;expires=' + expires.toUTCString()
    }
    /** 删除所有 Cookie */
    clear() {
        const cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
                let cookie = cookies[i];
                let eqPos = cookie.indexOf('=');
                let name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
                document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
        }
    }
    }


   const cookie = new Cookie()

image.png

可以使用js-cookie库进行操作

2.2 session

session是类似于cookie存储于服务器,有服务器生成可以返回给客户端进行存储,放入cookie中,必须是同源才能接收到

使用express进行搭建session生成存储

npm i express express-session cors -S

// index.js

const express = require('express');
const cors = require('cors')
const session = require('express-session');
const app = express();
app.use(cors())

// 将 public 目录设置为静态资源文件夹
app.use(express.static('public'));
// 设置 session 配置
app.use(
  session({
    secret: 'mySecretKey',
    resave: false,
    saveUninitialized: true,
    name:'sid' // 存储在客户端cookie中的键
  })
);

// 创建一个简单的路由,将访问次数存储在 session 中
app.get('/count', function (req, res) {
	console.log('打印***req.session.views',req.session.views)
  if (req.session.views) {
    req.session.views++;
    res.setHeader('Content-Type', 'text/html');
    res.write('<p>访问次数: ' + req.session.views + '</p>');
    res.end();
  } else {
    req.session.views = 1;
    res.end('欢迎您首次光临!请刷新页面查看访问次数');
  }
});

app.listen(3000, function() {
  console.log('服务启动在 http://localhost:3000');
});

启动服务,打开http://localhost:3000/count 存储在客户端的sessionId

image.png

2.2 webStorage

参考使用

2.3 Cache API

文档Experimental:  这是一个实验中的功能

caches.open('my-cache').then(function(cache) {
  var request = 'http://localhost:3000/cache';

  cache.match(request).then(function(response) {
    if (response) {
      return response;
    }

    return fetch(request).then(function(networkResponse) {
      cache.put(request, networkResponse.clone());
      return networkResponse;
    });
  }).then(function(response) {
    console.log(response);
  }).catch(function(error) {
    console.error(error);
  });
});


代码的执行逻辑如下:

  1. 调用caches.open('my-cache')方法打开一个名为"my-cache"的缓存。

  2. 调用cache.match(request)方法尝试从缓存中获取指定请求的资源。

  3. 如果在缓存中找到了资源,则直接返回缓存的响应。

  4. 如果在缓存中没有找到资源,继续执行下一步。

  5. 调用fetch(request)方法从网络获取请求的资源。

  6. 将请求响应存入缓存中,调用cache.put(request, networkResponse.clone())方法。

  7. 返回响应,即return networkResponse。

2.4 Service Worker

该代码段的作用是利用Service Worker中的缓存API,将请求过的资源存储在缓存中供以后使用,从而可以实现离线访问和性能优化等功能。

以下是一个使用Service Worker进行缓存和离线存储的示例,后端使用express进行搭建:

后端:

  1. 在项目目录中创建一个名为 index.js 的文件
// npm init -y 
// npm i express cors -S


const express = require('express');
const cors = require('cors')
const app = express();
app.use(cors())

// 将 public 目录设置为静态资源文件夹
app.use(express.static('public'));

app.get('/', function(req, res) {
  // res.send('Hello World!');
	 res.sendFile(__dirname + '/index.html');
});

app.listen(3000, function() {
  console.log('Example app listening on port 3000!');
});

这将设置一个简单的 Express 服务器,将静态文件提供在public目录中,并在根路由中处理请求。

  1. 创建名为 public 的目录,然后在其中创建两个文件 index.htmlsw.js

创建public文件夹

public
├─sw.js
├─styles
|   └main.css
├─scripts
|    └main.js

创建index.html文件

<!DOCTYPE html>
<html>
<head>
 <link rel="stylesheet" href="http://localhost:3000/styles/main.css" />
<script src="http://localhost:3000/scripts/main.js"></script>
 <title>Service Worker Caching Example</title>
</head>
<body>
  <h1>Service Worker Caching Example</h1>

  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', () => {
        navigator.serviceWorker
          .register('/sw.js')
          .then((registration) => {
            console.log('Service Worker Registered:', registration);
          })
          .catch((err) => {
            console.error('Service Worker Failed:', err);
          });
      });
    }
  </script>
</body>
</html>

这将注册 Service Worker 文件,即 sw.js

  1. 在 sw.js 中,进行基本的缓存操作:

sw.js

const CACHE_NAME = 'my-cache';
const urlsToCache = [
  '/',
  '/styles/main.css',
  '/scripts/main.js'
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then((cache) => {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then((response) => {
        if(response) {
          return response;
        }

        return fetch(event.request).then(
          (response) => {
            if (!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }

            const responseToCache = response.clone();

            caches.open(CACHE_NAME)
              .then((cache) => {
                cache.put(event.request, responseToCache);
              });

            return response;
          }
        );
      })
  );
});

self.addEventListener('activate', (event) => {
  const cacheWhitelist = [CACHE_NAME];

  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames.map((cacheName) => {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

接下来,让我们为前端添加一些功能以探索缓存的使用。在public目录中创建以下文件:

  1. styles/main.css
body {
    font-family: Arial, sans-serif;
    background-color: #f0f0f0;
}

.container {
    max-width: 800px;
    margin: 0 auto;
}
  1. scripts/main.js
document.addEventListener('DOMContentLoaded', () => {
    const updateCacheButton = document.createElement('button');
    updateCacheButton.innerText = 'Update Cache';

    const clearCacheButton = document.createElement('button');
    clearCacheButton.innerText = 'Clear Cache';

    const container = document.createElement('div');
    container.classList.add('container');
    container.appendChild(updateCacheButton);
    container.appendChild(clearCacheButton);

    document.body.appendChild(container);

    updateCacheButton.addEventListener('click', () => {
        fetch('/styles/main.css')
            .then(response => response.text())
            .then(css => console.log('CSS Fetched:', css));
    });

    clearCacheButton.addEventListener('click', () => {
        caches.delete('my-cache')
            .then(() => console.log('Cache Deleted'))
            .catch(err => console.error('Cache Deletion Error:', err));
    });
});

index.html文件中的<body>标签中,添加以下内容以访问刚刚添加的样式和脚本文件。

<link rel="stylesheet" href="/styles/main.css" />
<script src="/scripts/main.js"></script>

node index.js启动服务,然后访问 http://localhost:3000 查看已更新的示例。 你会看到两个按钮 "Update Cache" 和 "Clear Cache"。 当您点击 "Update Cache" 时,服务工作器会将 "/styles/main.css" 文件添加到缓存中,或者将现有的缓存项更新为新请求的响应。查看开发者工具的控制台,您可以看到请求到的 CSS 文件的内容。

点击 "Clear Cache" 按钮时,将删除名为 "my-cache" 的缓存。通过浏览器开发者工具查看 Cache Storage,您可以观察到缓存的删除。

第一次: image.png 离线设置: image.png

image.png

3. 区别

cookie、session和localStorage都是用于在浏览器端存储数据的技术,但它们在存储数据的方式、范围和安全性方面有所不同。

  1. Cookie

Cookie 是在客户端存储数据的最早的技术之一,其主要作用是跟踪用户在网站上的活动。4kb

  • 存储方式:Cookie 是通过 HTTP 请求从服务器发送到浏览器的一个小字符串,浏览器会将其存储在本地。在下一次请求时,该字符串会包含在请求头中,被服务器提取并分析。
  • 范围:Cookie 的作用域是被设置它的那个域名,它只能被同一域名下加载的页面读取。
  • 安全性:由于用户的个人信息通常会以明文方式存储在 Cookie 中,因此 Cookie 容易受到恶意攻击,特别是在不使用 HTTPS 安全协议的情况下。
  1. Session

与 Cookie 区别不大,Session 主要用于在服务器端存储用户信息。

  • 存储方式:Session 是通过在服务器上创建一个唯一的会话 ID 和存储相应的用户信息来创建的。在会话期间,客户端的请求会被绑定到该会话,并传递此唯一 ID。如果客户端关闭浏览器,会话将被销毁。
  • 范围:Session 的范围通常仅限于同一服务器上的网页。
  • 安全性:即使用户的 Session ID 被盗,攻击者也无法从服务器端访问用户的数据。不过,如果 Web 应用程序存在漏洞,则攻击者可以访问未加密的 Session 数据。
  1. localStorage

localStorage 是 HTML5 新增加的一种本地存储方式,可以完全由客户端使用。localStorage 主要用于永久性存储关键数据。5-10MB

  • 存储方式:localStorage 使用键值对的方式存储数据,数据仅限于字符串形式。存储到 localStorage 的数据永久生效,即使浏览器被关掉也不会清除。
  • 范围:localStorage 数据的作用域在同一浏览器,即使在打开同一域名二级页面的情况下,localStorage 的数据也可以被读取和修改。
  • 安全性:localStorage 是存在于浏览器缓存中的,因此容易受到恶意攻击。为了防止通过 XSS 攻击访问存储在 localStorage 中的敏感信息,可以使用加密和签名等安全措施。

总的来说,Cookie 用于存储跨页面的简单数据,Session 用于存储服务器端的用户信息,localStorage 用于永久性存储关键数据。应根据需求和应用程序的特点来选择合适的存储技术。

除了上述提到的 cookie、session 和 localStorage 外,浏览器还提供了以下几种存储方式:

  1. sessionStorage

sessionStorage 与 localStorage 非常相似,但数据仅在当前会话期间有效。如果用户关闭浏览器标签页或窗口,或者浏览器崩溃,则存储在 sessionStorage 中的数据将被清空。5-10MB

sessionStorage 使用方法与 localStorage 相同,只需将 "localStorage" 替换为 "sessionStorage" 即可。

  1. IndexedDB

IndexedDB 是浏览器本地数据库的标准 API,它可以在浏览器中存储大量、结构化的数据,比如 JSON 图形。IndexedDB 提供了一种异步事务的方式来处理数据的增删改查。

IndexedDB 的使用比较复杂,但在处理大量、复杂数据时非常有用。

  1. Web SQL Database

Web SQL Database 是一种轻量级的使用 SQL 的数据库系统,可以在浏览器中存储大量的结构化数据。Web SQL Database 具有类似于关系型数据库的特性,允许客户端查询数据并处理复杂的数据结构。

Web SQL Database 已被 Web 标准组织废弃和删除,但仍可在某些浏览器中使用。

  1. Service Worker

Service Worker 是一种比较新的浏览器存储技术,它是一种独立于网页本身的 JavaScript 运行环境,可以拦截网络请求、缓存资源和提供离线支持,使 Web 应用程序具有类似于本地应用程序的功能。

Service Worker 可以在后台更新缓存数据,并在用户重新访问页面时使用这些数据,从而提高应用程序的响应速度和性能。此外,Service Worker 还可以运行离线脚本、推送通知和执行一些高级任务,例如前台进程处理和数据同步等。

总的来说,浏览器还有很多存储技术可以选择,每种技术都有各自的优缺点和适用场景。根据应用程序的需求和平台支持情况,选择适合的存储技术是非常重要的。