前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • JavaScript Part 1

    • Ajax总结篇
    • Canvas 绘制八大行星
    • DOM编程之API学习总结篇
    • JavaScript事件机制
    • JavaScript代码片段100个
    • JavaScript作用域分析总结
    • JavaScript原型链回顾
    • JavaScript及jQuery中的各种宽高属性图解
    • JavaScript工程项目的一系列最佳实践
    • JavaScript常用API合集
    • JavaScript数组、字符串、对象常用方法
    • JavaScript数组方法总结篇
    • JavaScript深浅拷贝
    • JavaScript运动框架之速度时间版本
    • JavaScript运行机制Event Loop
    • JavaScript防抖节流原理
    • Javascript中的复制粘贴功能
    • Javascript数组详解
    • OOP之原型与原型链
    • Object.defineProperty详解
    • V8源码浅析JS数组常见方法
    • await 在 forEach 中不生效解决方案
    • iframe+表单跨域提交POST请求
    • javascript笔记总结篇
    • 业务中处理数据结构常用的JS方法
    • 作用域
    • 你真的掌握变量和类型了吗
    • 前后端分离之数据Mock
    • 原型与原型链
    • 原生JS补给(上)
    • 如何写出一个惊艳面试官的深拷贝
    • 带你填一些JS容易出错的坑
    • 彻底弄懂 JavaScript 执行机制
    • 执行上下文 执行栈
    • 正则回顾总结
    • 正则基础知识
    • 正则完整篇
    • 正则表达式
    • 浅析Promise原理
    • 浅谈JavaScript中的异步处理
    • 深拷贝 vs 浅拷贝
    • 聊一聊typeof instanceof 实现原理.
    • 聊一聊闭包
    • 高阶函数map reduce filter
  • JavaScript Part 2

  • CSS

  • HTML

  • Jquery

  • ES6

  • 小程序

  • Vue

  • React

  • 深入React

  • React Native

  • NodeJS

  • Angular

  • TypeScript

  • Webpack

  • 浏览器

  • 移动端

  • 前端工程化

  • Electron

  • HTTP

  • Nginx

  • Linux

  • 数据结构与算法

  • LeetCode算法题

  • 综合

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

HTTP Cookie篇|博客系列

# 本篇目录

通过阅读本篇文章你可以学习到:

  • Cookie概念
  • 产生原因
  • 关于Cookie的首部字段
  • 交互流程
  • 生命周期
  • 作用域
  • 安全性
  • 实际的用处
  • 缺点

# 1. Cookie概念

概念:通过在请求和响应报文中写入Cookie信息来控制客户端的状态,解决HTTP无状态的问题,本质就是存储在浏览器上一个很小的文本文件(也可能存在本地文件里)

# 2. 产生原因

HTTP是一种无状态协议,没法保存之前请求响应的上下文信息,但是对于一些场景来说需要用到之前的状态,所以为了解决这个问题产生了Cookie。但是它并不是为了解决通讯协议无状态的问题,而是为了解决客户端与服务端会话状态的问题,这个状态是指后段服务的状态而不是通讯协议的状态。

# 3. 关于Cookie的首部字段

关于Cookie的首部字段其实不太多,主要为:

  • Set-Cookie
  • Cookie

# 3.1 Set-Cookie

作用:在响应报文首部设置要传递给客户端的Cookie信息

例如:

Set-Cookie: name=xxx; HttpOnly
@前端进阶之旅: 代码已经复制到剪贴板

# 3.2 Cookie

作用:客户端传递给服务端的Cookie信息

例如:

Cookie: name=xxx
@前端进阶之旅: 代码已经复制到剪贴板

# 4. 交互流程

# 4.1 主要流程

客户端和服务器关于Cookie的交互流程如下:

  1. 客户端请求服务端
  2. 服务端生成Cookie信息使用 Set-Cookie 添加到响应报文头部上
  3. 客户端在拿到之后保存Cookie
  4. 在下次请求的时候通过把信息写入请求报文头部Cookie字段中传给服务端

# 4.2 设置Cookie的实际案例

光看上面👆说的可能有点迷糊,让我们结合一个实际的案例看看。

这里就以koa来模拟一个后台的登录接口,下面的代码主要做了四件事:

  • 设置响应的一些公共首部字段
  • 对每个请求做一些处理,例如登录接口则不验证token
  • 定义了一个名为/api/corsname的接口,用来获取名字
  • 定义了一个名为/api/login的接口,用来用户登录,并设置Cookie

./server.js:

const Koa = require("koa");
const router = require("koa-router")();
const koaBody = require("koa-body");
const app = new Koa();
const TOKEN = "112233"; // 模拟写死一个token

// 这里设置一些公共的首部字段
app.use(async (ctx, next) => {
  ctx.set("Access-Control-Allow-Origin", ctx.header.origin);
  ctx.set("Access-Control-Request-Method", "PUT,POST,GET,DELETE,OPTIONS");
  ctx.set(
    "Access-Control-Allow-Headers",
    "Origin, X-Requested-With, Content-Type, Access"
  );
  await next();
});

app.use(async (ctx, next) => {
  // 若是登录接口则跳过后面的token验证
  if (ctx.path === "/api/login") {
    await next();
    return;
  }
  // 对所有非登录的请求验证token
  const cookies = ctx.cookies.get("token");
  console.log(cookies);
  if (cookies && cookies === TOKEN) {
    await next();
    return;
  }
  ctx.body = {
    code: 401,
    msg: "权限错误",
  };
  return;
});
// 如果不加multipart:true ctx.request.body会获取不到值
app.use(koaBody({ multipart: true }));

router.get("/api/corsname", async (ctx) => {
  ctx.body = {
    data: "LinDaiDai",
  };
});

router.post("/api/login", async (ctx) => {
  ctx.cookies.set("token", TOKEN, { // 在此处设置 token
    expires: new Date(+new Date() + 1000 * 60 * 60 * 24 * 7),
  });
  ctx.body = {
    msg: "成功",
    code: 0,
  };
});

app.use(router.routes());
console.log("server 8080...");
app.listen(8080);
@前端进阶之旅: 代码已经复制到剪贴板

OK👌,来看看客户端(浏览器端)调用这两个接口的代码:

./index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CORS</title>
</head>
<body>
  <button id="getName">获取name</button>
  <button id="login">登录</button>
  <script src="https://cdn.bootcss.com/axios/0.19.2/axios.min.js"></script>
  <script>
    axios.defaults.baseURL = 'http://xxx.com'
    login.onclick = () => {
      axios.post('/api/login')
    }
    getName.onclick = () => {
      axios.get('/api/corsname').then(res => console.log(res.data))
    }
  </script>
</body>
</html>
@前端进阶之旅: 代码已经复制到剪贴板

此时,点击「登录」按钮,可以在/login这个接口的响应体中看到Set-Cookie这个首部字段:

(图里红色圈中的Access-Control-Allow-Credentials: true请忽略它,因为这张图是另一篇文章中拿来的,所以重点是Set-Cookie)

登录成功之后,点击「获取name」按钮,可以在/corsname这个接口的请求体中看到Cookie这个首部字段:

再来看看在浏览器中,我们可以如何查看Cookie:

# 5. 生命周期

在上面有介绍到关于Cookie的首部字段主要是Set-Cookie和Cookie,那有关于Cookie生命周期的首部字段的属性有哪些呢?也就是可以用什么来控制Cookie的生命周期。

  • 默认情况下Cookie是暂时存在的,也就是它们的存储只在浏览器会话期间存在,当用户在关闭浏览器时失效
  • 可以使用expires和max-age来设置Cookie的过期时间

# 5.1 expires=DATE

作用:给Cookie 设置过期时间,一个具体的时间。

默认值:默认为设置的expires的当前时间。

案例:

例如后端代码中:

ctx.cookies.set("token", '112233', {
	expires: new Date(+new Date() + 1000 * 60 * 60 * 24 * 7),
});
@前端进阶之旅: 代码已经复制到剪贴板

此时接口请求的响应体的首部字段带有:

Set-Cookie: token=112233; expires=Wed Aug 12 2020 21:55:03 GMT
@前端进阶之旅: 代码已经复制到剪贴板

# 5.2 max-age=TIME

作用:给Cookie设置过期时间,一段时间,单位是秒,从客户端收到报文开始计算。

默认值:-1。

使用方式与expires一样:

例如后端代码中:

ctx.cookies.set("token", '112233', {
	max-age: 36000,
});
@前端进阶之旅: 代码已经复制到剪贴板

此时接口请求的响应体的首部字段带有:

Set-Cookie: token=112233; max-age=36000	
@前端进阶之旅: 代码已经复制到剪贴板

另外,属性值分为以下三种,方便记忆:

  • 0:立即删除这个Cookie
  • 正数:浏览器将其持久化写入Cookie中
  • 负数:会话性Cookie

针对于上面👆的三种情况,面试时可能会碰到的问题:

# Q1: cookie的max-age属性设置为0会怎样?

A:如果max-age为0,则表示删除该cookie。cookie机制没有提供删除cookie的方法,因此通过设置该cookie即时失效实现删除cookie的效果。失效的Cookie会被浏览器从cookie文件或者内存中删除。

# Q2:设置了cookie的max-age属性为正数,关闭浏览器会怎样?

A:如果max-age属性为正数,则表示该cookie会在max-age秒之后自动失效。浏览器会将max-age为正数的cookie持久化,即写到对应的cookie文件中。无论客户关闭了浏览器还是电脑,只要还在max-age秒之前,登录网站时该cookie仍然有效。

# Q3:设置了cookie的max-age属性为负数,会怎样?

A:如果max-age为负数,则表示该cookie仅在本浏览器窗口以及本窗口打开的子窗口内有效,关闭窗口后该cookie即失效。max-age为负数的Cookie,为临时性cookie,不会被持久化,不会被写到cookie文件中。cookie信息保存在浏览器内存中,因此关闭浏览器该cookie就消失了。cookie默认的max-age值为-1。

# 6. 作用域

作用域概念:对于Cookie的作用域,表示的是给Cookie绑定域名和路径,在发送请求之前若是发现域名或者路径这两个属性不匹配则不会携带Cookie,通俗来说就是在哪些情况下携带Cookie。

有关于Cookie作用域的首部字段有哪些呢?

  • domain=域名
  • path=PATH

# 6.1 domain=域名

作用:指定Cookie可以送达的主机名。

例如:

Set-Cookie: domain=.example.com
@前端进阶之旅: 代码已经复制到剪贴板

# 6.2 path=PATH

作用:指定一个URL路径,Cookie首部只会被添加到这个指定URL路径的请求报文首部上。

默认值为:/,也就是所有URL路径都会携带Cookie。

例如设置了:

Set-Cookie: name=xxx; path=/docs
@前端进阶之旅: 代码已经复制到剪贴板

那么只有/docs 下的资源才会带有Cookie,而另一个名为/test 的目录下就没有。

# 7. 安全性

Cookie的安全性也是一个常问的点,这方面涉及到的首部字段的属性主要有:

  • Secure
  • HttpOnly
  • SameSite

# 7.1 Secure

作用:设置了secure属性,表示Cookie只在HTTPS下传输。

例如:

Set-Cookie: name=xxx; secure
@前端进阶之旅: 代码已经复制到剪贴板

让我们来看一个实际的运用场景。

前提条件: https://lindaidai.com 对cookie设置了secure=true属性。

← CORS原理及实现HTTP协议系列(一) →

fe
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片NEW
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 业务场景题真实业务问题与追问
  • 查漏补缺常见问题解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
    • AI 定制路线NEW按你的简历现排
    • AI 知识地图NEW串起全站知识点
  • 动态
    • AI 热点NEWAI 每日动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
AI 助手NEW
旧版
  • JavaScript Part 1

    • Ajax总结篇
    • Canvas 绘制八大行星
    • DOM编程之API学习总结篇
    • JavaScript事件机制
    • JavaScript代码片段100个
    • JavaScript作用域分析总结
    • JavaScript原型链回顾
    • JavaScript及jQuery中的各种宽高属性图解
    • JavaScript工程项目的一系列最佳实践
    • JavaScript常用API合集
    • JavaScript数组、字符串、对象常用方法
    • JavaScript数组方法总结篇
    • JavaScript深浅拷贝
    • JavaScript运动框架之速度时间版本
    • JavaScript运行机制Event Loop
    • JavaScript防抖节流原理
    • Javascript中的复制粘贴功能
    • Javascript数组详解
    • OOP之原型与原型链
    • Object.defineProperty详解
    • V8源码浅析JS数组常见方法
    • await 在 forEach 中不生效解决方案
    • iframe+表单跨域提交POST请求
    • javascript笔记总结篇
    • 业务中处理数据结构常用的JS方法
    • 作用域
    • 你真的掌握变量和类型了吗
    • 前后端分离之数据Mock
    • 原型与原型链
    • 原生JS补给(上)
    • 如何写出一个惊艳面试官的深拷贝
    • 带你填一些JS容易出错的坑
    • 彻底弄懂 JavaScript 执行机制
    • 执行上下文 执行栈
    • 正则回顾总结
    • 正则基础知识
    • 正则完整篇
    • 正则表达式
    • 浅析Promise原理
    • 浅谈JavaScript中的异步处理
    • 深拷贝 vs 浅拷贝
    • 聊一聊typeof instanceof 实现原理.
    • 聊一聊闭包
    • 高阶函数map reduce filter
  • JavaScript Part 2

  • CSS

  • HTML

  • Jquery

  • ES6

  • 小程序

  • Vue

  • React

  • 深入React

  • React Native

  • NodeJS

  • Angular

  • TypeScript

  • Webpack

  • 浏览器

  • 移动端

  • 前端工程化

  • Electron

  • HTTP

  • Nginx

  • Linux

  • 数据结构与算法

  • LeetCode算法题

  • 综合