Skip to content

会话控制

作者:青见春山
发表于:2026-09-08
字数统计:2185 字
预计阅读8分钟

介绍

所谓会话控制就是 对会话进行控制

HTTP 是一种无状态的协议,它没有办法区分多次的请求是否来自于同一个客户端,无法区分用户

而产品中又大量存在的这样的需求,所以我们需要通过 会话控制 来解决该问题

常见的会话控制技术有三种:

  • cookie
  • session
  • token

cookie 是 HTTP 服务器发送到用户浏览器并保存在本地的一小块数据

cookie 是保存在浏览器端的一小块数据

cookie 是按照域名划分保存的

简单示例:

域名cookie
www.baidu.coma=100; b=200
www.bilibili.comxid=1020abce121; hm=112411213
jd.comx=100; ocw=12414cce

浏览器向服务器发送请求时,会自动将 当前域名下 可用的 cookie 设置在请求头中,然后传递给服务器

11_会话控制

HTTP 请求中的 Cookie 头用于携带匹配的 Cookie 键值对;响应中的 Set-Cookie 用于创建或更新 Cookie。浏览器保存的 Cookie 记录与传输它们的头字段有关,但不是同一个概念。

填写账号和密码校验身份,校验通过后下发 cookie

image-20230327214116490 有了 Cookie 之后,浏览器只会在 Domain/主机、Path、Secure、SameSite、过期时间等条件匹配时自动携带它,并非所有后续请求都会携带。

image-20230327214554199

浏览器操作 cookie 的操作,使用相对较少,大家了解即可

  1. 禁用所有 cookie
  2. 删除 cookie
  3. 查看 cookie

Express 自带 res.cookie()/res.clearCookie() 用于写响应;读取并解析 req.cookies 时可以使用 cookie-parser

js
const express = require("express");
//1. 安装 cookie-parser	 npm i cookie-parser
//2. 引入 cookieParser 包
const cookieParser = require("cookie-parser");

const app = express();

//3. 设置 cookieParser 中间件
app.use(cookieParser());

//4-1 设置 cookie
app.get("/set-cookie", (request, response) => {
  // 不带时效性    会在浏览器关闭的时候,销毁
  response.cookie("username", "wangwu");
  // 带时效性
  response.cookie("email", "23123456@qq.com", { maxAge: 5 * 60 * 1000 });
  //响应
  response.send("Cookie的设置");
});

//4-2 读取 cookie
app.get("/get-cookie", (request, response) => {
  //读取 cookie
  console.log(request.cookies);
  //响应体
  response.send("Cookie的读取");
});

//4-3 删除cookie
app.get("/delete-cookie", (request, response) => {
  //删除
  response.clearCookie("username");
  //响应
  response.send("cookie 的清除");
});

//4. 启动服务
app.listen(3000, () => {
  console.log("服务已经启动....");
});

不同浏览器中的 cookie 是相互独立的,不共享

session

session 是什么

session 是保存在 服务器端的一块儿数据,保存当前访问用户的相关信息

session 的作用

实现会话控制,可以识别用户的身份,快速获取当前用户的相关信息

session 运行流程

填写账号和密码校验身份,校验通过后创建 session 信息,然后将 session_id 的值通过响应头返回给浏览器

image-20230327222810111

有了cookie,下次发送请求时会自动携带cookie,服务器通过 cookie 中的 session_id 的值确定用 户的身份

image-20230327223550720

session 的代码操作

express 中可以使用 express-session 对 session 进行操作

js
const express = require("express");
//1. 安装包 npm i express-session connect-mongo
//2. 引入 express-session connect-mongo
const session = require("express-session");
const MongoStore = require("connect-mongo");

const app = express();

//3. 设置 session 的中间件
app.use(
  session({
    name: "sid", //设置cookie的name,默认值是:connect.sid
    secret: process.env.SESSION_SECRET, //用于签名 Session ID Cookie,不是加密;生产环境从安全配置读取
    saveUninitialized: false, //是否为每次请求都设置一个cookie用来存储session的id
    resave: false, //存储支持 touch 时通常设为 false,避免未修改的 session 被重复写入
    store: MongoStore.create({
      mongoUrl: "mongodb://127.0.0.1:27017/project", //数据库的连接配置
    }),
    cookie: {
      httpOnly: true, // 页面脚本无法通过 document.cookie 读取,但仍可发起自动携带 Cookie 的请求
      secure: true, // 生产 HTTPS 环境启用;反向代理后还需正确配置 trust proxy
      sameSite: "lax",
      maxAge: 1000 * 300, // 这一条 是控制 sessionID 的过期时间的!!!
    },
  }),
);

//创建 session  session的设置
app.get("/login", (req, res) => {
  //设置session
  req.session.username = "zhangsan";
  req.session.email = "zhangsan@qq.com";
  res.send("登录成功");
});

//获取 session
app.get("/home", (req, res) => {
  console.log("session的信息");
  console.log(req.session.username);
  // 检测 session 是否存在用户数据
  if (req.session.username) {
    res.send(`你好 ${req.session.username}`);
  } else {
    res.send("登录 注册");
  }
});

//销毁 session
app.get("/logout", (req, res) => {
  //销毁session
  // res.send('设置session');
  req.session.destroy(() => {
    res.send("成功退出");
  });
});
app.listen(3000, () => {
  console.log("服务已经启动, 端口 " + 3000 + " 监听中...");
});

cookie 和 session 的区别主要有如下几点:

  1. 存在的位置
  • cookie:浏览器端
  • session:服务端
  1. 安全性
  • Cookie 内容由客户端持有,服务端不能信任未经签名或校验的值;敏感 Cookie 应结合 TLS、HttpOnly、Secure、SameSite 和合理过期策略
  • Session 数据通常存于服务器,但 Session ID Cookie 仍是可被劫持的凭证;安全性不能只由存储位置判断
  1. 网络传输量
  • cookie 设置内容过多会增大报文体积, 会影响传输效率
  • session 通常只通过 Cookie 传递 ID,报文增量较小但不为零;服务端还会产生存储和查询开销
  1. 存储限制
  • 浏览器限制单个 cookie 保存的数据不能超过 4K ,且单个域名下的存储数量也有限制
  • session 不受单个 Cookie 约 4 KiB 的同一限制,但仍受服务端存储容量、序列化、数据库文档大小和应用配置约束

token

token 是什么

Token 是客户端向资源服务器出示的凭证。它可以是不透明随机串,也可以是 JWT;不保证经过加密,也不一定直接包含用户信息。

token 不属于 http 标准,完全由前后端协商而定,但 cookie 属于 http 标准

token 的作用

Token 可用于认证或授权,Web、移动端和服务间调用都很常见,并非主要用于移动端 App。

token 的工作流程

填写账号和密码校验身份,校验通过后响应 token,token 一般是在响应体中返回给客户端的

image-20230328135106885 后续发送请求时,需要手动将 token 添加在请求报文中(cookie是自动携带的),一般是放在请求头中 image-20230328135122945

token 的特点

  • 是否减少服务端压力取决于方案。不透明 Token 通常仍需查存储;JWT 即使可离线验签,也可能需要查询用户状态或撤销记录

  • Token 不天然更安全,也不天然加密。JWT 常见的 JWS 只是签名,载荷可被读取

  • CSRF 风险取决于凭证如何发送:放在自动携带的 Cookie 中仍需 CSRF 防护;由脚本放入 Authorization 头可降低传统 CSRF 风险,但会暴露于 XSS

  • 扩展性更强

    • 服务间可以共享
    • 增加服务节点更简单

JWT

JWT(JSON Web Token )是目前最流行的跨域认证解决方案,可用于基于 token 的身份验证

JWT 使 token 的生成与校验更规范

我们可以使用 jsonwebtoken 包 来操作 token

js
//导入 jsonwebtokan
const jwt = require("jsonwebtoken");

//创建 token
// jwt.sign(payload, 签名密钥, 配置对象):默认生成签名 JWT,不是加密 JWT
let token = jwt.sign(
  {
    username: "zhangsan",
  },
  "atguigu",
  {
    expiresIn: 60, //单位是 秒
  },
);

//解析 token
// jwt.verify(token, 签名密钥, 回调函数)
jwt.verify(token, "atguigu", (err, data) => {
  if (err) {
    console.log("校验失败~~");
    return;
  }
  console.log(data); // { username: '张三', iat: (创建时间), exp:(过期时间)}
});

扩展阅读: https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

附录

本地域名

所谓本地域名就是 只能在本机使用的域名,一般在开发阶段使用

操作流程

编辑文件 C:\Windows\System32\drivers\etc\hosts

127.0.0.1   www.baidu.com

如果修改失败,可以修改该文件的权限

11_会话控制

原理

在地址栏输入 域名 之后,浏览器会先进行 DNS(Domain Name System)查询,获取该域名对应的 IP 地 址 请求会发送到 DNS 服务器,可以 根据域名返回 IP 地址

可以通过 ipconfig /all 查看本机的 DNS 服务器

hosts 文件也可以设置域名与 IP 的映射关系,在发送请求前,可以通过该文件获取域名的 IP 地址