HTTP 无状态

# HTTP 无状态

首先 HTTP 是无状态的,第二次浏览某一个网页时,服务器也没发现是同一个人浏览的,但是现实当中肯定不似乎这样的,这就要引出 Web 中的存储问题。

首先 Cookie 就是一种存储机制而已。

# 描述

  1. 当我们第一次请求网页内容的时候是没有任何 Cookie 的;
  2. 服务器在收到请求以后会在 HTTP 响应头里添加头部 Set-Cookie,并且在 Set-Cookie 进行标识;
  3. 在下一次请求的时候浏览器就会在 HTTP 请求里添加头部 Cookie,并且用上 Set-Cookie 里的标识;
  4. 这样服务器就可以给不同用户匹配不同的内容了;

但是每次请求服务器,浏览器都会自动把 Cookie 添加到响应头,如果每一次都要把含有大量数据的 Cookie 发送给服务器,无疑是一种自杀行为,因此把 Cookie 设计的很小,不能超过 4KB(大部分情况会更小)。

# 案例——登陆页面

<form>
  <label for="">用户名</label>
  <input type="username" />
  <label for="">密码</label>
  <input type="password" />
  <input type="checkbox" id="rememberMe" />
  <label for="rememberMe">记住我</label>
  <input type="submit" value="登陆" />
</form>
<script>
  // 获取DOM元素
  const username = document.querySelector('input[type="username"]');
  const checkbox = document.querySelector('input[type="checkbox"]');
  const submit = document.querySelector('input[type="submit"]');

  // 判断是否有Cookie,并将内容填到相应的输入框中
  if (document.cookie) {
    username.value = cookie.username;
    checkbox.checked = true;
  }

  // 拆分该网页下的Cookie
  let arr = document.cookie.split(";").map((cookie) => cookie.split("="));
  let cookie = {};
  for (let i = 0; i < arr.length; i++) {
    let name = arr[i][0];
    let value = arr[i][1];
    cookie[name] = decodeURIComponent(value);
  }
  console.log(cookie);

  submit.addEventListener("click", (e) => {
    if (checkbox.checked && username.value != "") {
      let key = "username";
      let value = encodeURIComponent(username.value);
      let twoDays = 2 * 24 * 60 * 60;
      document.cookie = `${key}=${value}; max-age=${twoDays}`;
    }
    // 点击提交之后,浏览器会默认刷新界面
    e.preventDefault();
  });
</script>

# 发展

随着网页内容的丰富,有些个人设置服务器并不需要获取,完全可以保存在客户端里,HTML5 的出现:localStorage 和 sessionStorage。第一次请求服务器时,服务器响应内容,并附加可以操作网页的 js,浏览器执行这些 JS,个人设置就可以通过 Web 存储机制保存在浏览器里了。

# localStorage

# 描述

永久保存,可以手动删除。虽然保存下来了,但他本身不参与服务器通信,存储容量大很多,但 localStorage 是同步机制,会影响浏览器渲染进度。

# 案例——历史搜索记录

<input type="text" />
<section><ul class="history"></ul></section>
<button>搜索</button>

<script>
  const input = document.querySelector('input[type="text"]');
  const button = document.querySelector("button");
  // 用来存放历史纪录的列表
  const history = document.querySelector(".history");

  // 网页加载时,如果localStorage中的length大于0,就显示历史记录
  if (localStorage.length > 0) {
    for (let i = 0; i < localStorage.length; i++) {
      let key = localStorage.key(i);
      let li = document.createElement("li");
      let liText = document.createTextNode(localStorage.getItem(key));
      li.appendChild(liText);
      history.appendChild(li);
      let close = document.createElement("sapn");
      li.append(close);
      close.addEventListener("click", () => {
        localStorage.removeItem(key);
        li.parentNode.removeChild(li);
      });
    }
  }

  button.addEventListener("click", () => {
    // 如果输入框不为空
    if (input.value) {
      let key = new Date().valueOf();
      let value = input.value;
      // 把搜索记录存到localStorage中
      localStorage.setItem(key, value);
      input.value = "";

      let li = document.createElement("li");
      let liText = document.createTextNode(localStorage.getItem(key));
      li.appendChild(liText);
      history.appendChild(li);

      // 同时增加删除历史记录按键
      let close = document.createElement("span");
      li.append(close);
      close.addEventListener("click", () => {
        // 删除localStorage中对应key的历史记录
        localStorage.removeItem(key);
        li.parentNode.removeChild(li);
      });
    }
  });
</script>

# sessionStorage

# 描述

语法基本语 localStorage 一致,但是打开新的窗口,sessionStorage 中的内容就没了。

# 总结

cookie localStorage sessionStorage
大小 4kb 10mb 5mb
兼容 H4/H5 H5 H5
访问 任何窗口 任何窗口 同一窗口
有效期 手动设置 到窗口关闭
存储位置 浏览器和服务器 浏览器 浏览器
与请求一起发送
语法 复杂 简易 简易