为啥有的网站登了之后不用再次登录?--来讲讲浏览器中的存储

657 阅读5分钟

前言

在当今的网络时代,数据存储和管理是Web开发中不可或缺的一部分。从用户偏好设置到登录状态,Web应用需要一种方式来存储和检索信息,以提供流畅和个性化的用户体验。本文将深入探讨几种常见的Web存储技术:localStoragesessionStorage、Cookies以及IndexedDB。这些技术各有特点,适用于不同的应用场景。通过理解它们的工作原理和使用方式,开发者可以更有效地管理Web应用中的数据存储需求。

正文

localStorage

我们登录掘金,数据正是通过这种方式存储的。就算我们把页面关了,电脑重启了,数据也还在,不会让我们重新输入账号密码登录。

特点

  1. 时效性:永久有效,浏览器本地存储, 需要手动清理浏览器缓存才会失效
  2. 存储为一个对象,且只能是字符串
  3. 存储空间大约5M
  4. 为每一个域名开辟的存储空间
<button id="save">保存</button>
  <button id="get">读取</button>
  <button id="delete">删除</button>
  <button id="clear">清空</button>
  <script>
    const user = {
      name: 'JS',
      age: 22
    }
  </script>

保存

setItem(key,value)

 document.getElementById('save').addEventListener('click', () => {
      localStorage.setItem('userV', JSON.stringify(user))//本地存储
    })

image.png

读取

getItem(key)

    document.getElementById('get').addEventListener('click', () => {
      console.log(JSON.parse(localStorage.getItem('userV'))); // 打印获取到的用户信息
    });

image.png

移除

removeItem(key)

   document.getElementById('delete').addEventListener('click', () => {
     localStorage.removeItem('userV');//移除userV
   });

image.png

image.png

清空

clear()

    document.getElementById('clear').addEventListener('click', () => {
      localStorage.clear();//清空存储的数据
    });

image.png

sesstionStorage

时效性:当前这次会话结束就会自动销毁

保存

    document.getElementById('save').addEventListener('click', () => {
      sessionStorage.setItem('userV', JSON.stringify(user))
    })

如果我们写成sessionStorage.setItem('key', user),会存不进去一个对象 image.png

所以该改成sessionStorage.setItem('userV', JSON.stringify(user))

image.png

读取

    document.getElementById('get').addEventListener('click', () => {
      console.log(sessionStorage.getItem('key'));
    });

image.png

移除

    document.getElementById('delete').addEventListener('click', () => {
      sessionStorage.removeItem('userV')
    });

image.png

清空

    document.getElementById('clear').addEventListener('click', () => {
      sessionStorage.clear()
    });

image.png

Session Storage 的特点是此次会话结束,存储的数据也会清除掉

这是Local Storage image.png 页面重启后: image.png 没变化

这是Session Storage image.png 页面重启后:

image.png

数据都清掉了

Cookies

Cookies 是一种由服务器发送到客户端浏览器并保存在本地的小型数据存储对象。它们确实用于识别用户身份、跟踪用户在网站上的行为以及保存用户的偏好设置等。Cookies主要分为两种类型:

  1. 会话Cookies(Session Cookies)

    • 它们确实存储在浏览器的内存中,而不是硬盘上。
    • 当用户关闭浏览器窗口或标签页时,会话Cookies 会被自动删除。
    • 它们通常用于存储会话期间的临时数据,如购物车中的商品、用户登录状态等。
  2. 持久Cookies(Persistent Cookies)

    • 这些Cookies 存储在用户的硬盘上,并且有一个设定的过期时间。
    • 即使关闭浏览器,它们也会保留在用户的设备上,直到过期或被用户手动删除。
    • 它们用于存储用户的长期偏好,如语言选择、主题设置等。

关于安全性,Cookies 本身并不是特别安全,因为它们可以被读取或篡改。但是,通过一些措施可以提高安全性,比如:

  • 使用HTTPS协议来加密Cookies在传输过程中的数据。
  • 设置HttpOnly属性,这样JavaScript就无法访问Cookies,从而减少跨站脚本攻击(XSS)的风险。
  • 设置Secure属性,确保Cookies 仅通过HTTPS传输,防止在不安全的HTTP连接中被截获。

总的来说, Cookies不受前端掌控(更安全),由后端控制

IndexedDB

一种在浏览器中存储大量结构化数据的低级 API

特点

  1. 浏览器提供的本地数据库
  2. 异步
  3. 支持使用js编写逻辑来创建,打开,插入,查询,删除 IndexedDB中的数据库
  4. 键值对存储
  5. 大容量 无上限
  6. 永久存储

示例

<button onclick="openDB()">连接数据库</button>
  <button onclick="createDB()">新建数据库</button>
  <button onclick="insertOneDB()">插入一条数据</button>
  <button onclick="insertMultiDB()">插入多条数据</button>
  <button onclick="queryDB()">查询数据</button>
  <button onclick="updateDB()">更新数据</button>
  <div id="table"></div>

  <script>
    const dbName = 'users'
    const dbVersion = 1.0
    let db = null

    function openDB() {
      const request = indexedDB.open(dbName, dbVersion)
      request.onerror = function () {
        console.log('无法打开数据库');
      }

      request.onupgradeneeded = function (event) {
        db = event.target.result
        // 创建一个表
        const objectStore = db.createObjectStore(['sex'], { keyPath: 'id' })
        objectStore.createIndex('title', 'title', { unique: true })
      }

      request.onsuccess = function (event) {
        // console.log(event);
        db = event.target.result
        console.log(`数据库${db.name}已经开启`);
      }
    }

    function insertOneDB() {
      console.log(db);
      const transaction = db.transaction(['sex'], 'readwrite')
        .objectStore('sex')
        .add({ id: 1, title: '男生', author: '张三', createAt: Date.now() })

      transaction.onerror = function () {
        console.log('数据写入失败');
      }
      transaction.onsuccess = function () {
        console.log('数据写入成功');
      }
    }

    function insertMultiDB() {
      const data = [
        { id: 2, title: '男生1', author: '李四', createAt: Date.now() },
        { id: 3, title: '男生2', author: '王五', createAt: Date.now() },
        { id: 4, title: '女生', author: '裴珠泫', createAt: Date.now() }
      ]

      const transaction = db.transaction('sex', 'readwrite')
      const objectStore = transaction.objectStore('sex')
      data.forEach((item) => {
        const request = objectStore.add(item)
        request.onsuccess = function () {
          console.log('数据已添加');
          db.close()
        }
      })
    }

    function queryDB() {
      const transaction = db.transaction(['sex'], 'readonly')
      const objectStore = transaction.objectStore('sex')
      const index = objectStore.index('title')

      const range = IDBKeyRange.only('女生')
      const request = index.openCursor(range)

      request.onsuccess = function (event) {
        console.log(event.target.result.value);
      }
    }


    function updateDB() {
      const transaction = db.transaction(['sex'], 'readwrite');
      const objectStore = transaction.objectStore('sex');
      const idToUpdate = 1; 
      const getRequest = objectStore.get(idToUpdate);
      
      getRequest.onsuccess = function (event) {
        const originalData = event.target.result;
        originalData.author = '胡歌'; 
        const putRequest = objectStore.put(originalData);
        
        putRequest.onsuccess = function () {
          console.log('数据更新成功');
        };
        putRequest.onerror = function () {
          console.error('数据更新失败');
        };
      };

      // 错误处理
      getRequest.onerror = function () {
        console.error('获取数据失败');
      };
    }
  </script>

这段代码比较长,我们解释一下:

  1. 初始化数据库 (openDB): 这个函数尝试打开或创建一个名为users的数据库。如果数据库不存在,会触发onupgradeneeded事件,此时会创建一个名为sex的对象仓库,并为其添加一个唯一索引title
  2. 插入一条记录 (insertOneDB): 插入一条包含id、title、author和createAt字段的记录到sex对象仓库中。
  3. 批量插入记录 (insertMultiDB): 插入多条记录,每条记录包含id、title、author和createAt字段。插入后,数据库会被关闭。
  4. 查询记录 (queryDB): 查询sex对象仓库中title女生的记录。使用openCursor方法并指定IDBKeyRange,以便精确查询。

请注意,代码中的一些细节可能需要修正以确保正确的功能:

  • insertOneDB函数中,transaction.objectStore('sex')应直接用于add方法,而不是transaction
  • insertMultiDB函数中,transaction应该是db.transaction(['sex'], 'readwrite'),并且在data.forEach循环外关闭数据库可能不是必要的,尤其是当所有操作都在一个事务中完成时。
  • queryDB函数中,request.onsuccess回调函数内的console.log可能需要检查event.target.result是否存在,以避免潜在的undefined错误。

代码中还有没写完的createDBupdateDB函数也要实现具体的数据库创建和数据更新逻辑。

连接数据库:

    function openDB() {
      const request = indexedDB.open(dbName, dbVersion)
      request.onerror = function () {
        console.log('无法连接数据库');
      }

      request.onupgradeneeded = function (event) {
        db = event.target.result
        // 创建一个表
        const objectStore = db.createObjectStore(['sex'], { keyPath: 'id' })
        objectStore.createIndex('title', 'title', { unique: true })
      }

      request.onsuccess = function (event) {
        // console.log(event);
        db = event.target.result
        console.log(`数据库${db.name}已连接`);
      }
    }

image.png

image.png

插入一条数据:

    function insertOneDB() {
      console.log(db);
      const transaction = db.transaction(['sex'], 'readwrite')
        .objectStore('sex')
        .add({ id: 1, title: '男生', author: '张三', createAt: Date.now() })

      transaction.onerror = function () {
        console.log('数据写入失败');
      }
      transaction.onsuccess = function () {
        console.log('数据写入成功');
      }
    }

image.png

image.png

插入多条数据:

    function insertMultiDB() {
      const data = [
        { id: 2, title: '男生1', author: '李四', createAt: Date.now() },
        { id: 3, title: '男生2', author: '王五', createAt: Date.now() },
        { id: 4, title: '女生', author: '裴珠泫', createAt: Date.now() }
      ]

      const transaction = db.transaction('sex', 'readwrite')
      const objectStore = transaction.objectStore('sex')
      data.forEach((item) => {
        const request = objectStore.add(item)
        request.onsuccess = function () {
          console.log('数据已添加');
          db.close()
        }
      })
    }

image.png

image.png

查找数据:

  function queryDB() {
      const transaction = db.transaction(['sex'], 'readonly')
      const objectStore = transaction.objectStore('sex')
      const index = objectStore.index('title')

      const range = IDBKeyRange.only('女生')
      const request = index.openCursor(range)

      request.onsuccess = function (event) {
        console.log(event.target.result.value);
      }

image.png

更新数据:

function updateDB() {
      // 假设db是我们已经打开的数据库实例
      const transaction = db.transaction(['sex'], 'readwrite');
      const objectStore = transaction.objectStore('sex');

      const idToUpdate = 1; // 假设我们要更新id为1的记录

      // 使用get方法获取记录
      const getRequest = objectStore.get(idToUpdate);

      // 当请求完成时,我们获取到原始数据
      getRequest.onsuccess = function (event) {
        const originalData = event.target.result;

        // 更新数据
        originalData.author = '胡歌'; // 修改title字段

        // 使用put方法保存更改后的数据
        const putRequest = objectStore.put(originalData);

        putRequest.onsuccess = function () {
          console.log('数据更新成功');
        };

image.png

Web SQL

浏览器上的模拟数据库(已弃用)

总结

通过本文的探讨,我们对Web存储技术有了全面的了解。

localStorage提供了一个简单易用的方式来存储长期数据,但需要注意数据大小和类型限制。

sessionStorage则适用于存储临时数据,其生命周期仅限于浏览器会话。

Cookies作为一种历史悠久的技术,虽然在现代Web应用中的使用有所减少,但仍然是处理用户身份和会话状态的重要工具。

IndexedDB以其强大的能力,为需要存储大量结构化数据的应用提供了解决方案。

每种技术都有其优势和局限性,选择合适的存储方式取决于应用的具体需求。随着Web技术的不断发展,这些存储技术也在不断进化,以满足日益增长的数据管理需求。作为开发者,了解并合理利用这些技术,将有助于构建更加强大和用户友好的Web应用