主题
会话控制与会话控制介绍(Day13 1/3)
本页对应 Day13_Node&会话控制,共 7 段视频,约 1 小时 44 分。
学习目标
- 能够解释 HTTP 协议无状态特性带来的登录状态识别问题,并说明会话控制的作用。
- 能够描述 Cookie 的设置、携带、读取和删除流程,区分响应头与请求头在其中的作用。
- 能够使用 Express 与 cookie-parser 完成 Cookie 的设置、读取、删除,并演示域名限制、有效期等属性效果。
- 能够列举 Cookie 在数量容量限制、请求流量增加和客户端可篡改方面的缺点。
- 能够解释 Session 将数据存储在服务端、通过 Cookie 保存 Session ID 进行客户端匹配的实现原理。
- 能够使用 express-session 完成 Session 的初始化配置、设置、读取、删除单个数据及销毁会话。
知识点
为什么需要会话控制
HTTP 协议是无状态的。站在服务器角度,它只关心“你请求了什么路径”,并不天然记得“这次请求和上次请求是不是同一个浏览器”。转写稿里反复强调:上一次你登录过,下一次请求时服务器并不知道,这样登录就失去意义。所以需要会话控制,把登录状态“记住”。
怎么想:会话控制的目标不是让服务器认识“人”,而是识别“浏览器客户端”。常见方案有 cookie、session、token;cookie/session 依赖浏览器,token 常被用于脱离浏览器的场景。今天重点用代码理解 cookie 与 session 的流程。
怎么做:先看 cookie 如何把状态存在浏览器,再看 session 如何把主要数据放服务器、只让浏览器保存一个 session ID。
易错点:不要把“会话”写成“绘画/互画”;不要以为服务器天然记得登录状态。
Cookie 的设置与携带流程
为什么需要:cookie 是最直观的方案——登录成功后,把状态记到浏览器上,下次请求自动带上。
怎么想:谁决定设置 cookie?服务器。谁真正操作?浏览器。服务器通过响应头 Set-Cookie 告诉浏览器怎么存;浏览器后续请求时通过请求头 Cookie 自动带回。
怎么做:转写稿在百度页面按 F12 打开“应用/Application”查看 Cookie,清空后刷新,登录状态就丢了;说明登录状态确实依赖浏览器里的 cookie。不同网站、不同浏览器之间 cookie 隔离;127.0.0.1 与 localhost 默认也不共享。
易错点:cookie 以域名隔离;默认有效期是浏览器关闭即失效;maxAge 在后端 JS 里是毫秒,浏览器调试面板常显示为秒/失效时间。
用 Express 演示 Cookie
为什么需要:实际工作很少手写响应头,但必须理解 Set-Cookie 与 Cookie 的对应关系。
怎么想:用中间件给 req/res 增加 cookie 处理方法,设置时加到响应对象,读取时从请求对象取。
怎么做:安装 express 与 cookie-parser,写三个路由:设置、查看、删除。
js
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
app.get('/set', (req, res) => {
res.cookie('username', 'admin', { maxAge: 3600 * 1000 });
res.cookie('userId', '1001');
res.cookie('address', '北京', { maxAge: 3600 * 1000 });
res.send('cookie设置成功');
});
app.get('/get', (req, res) => {
console.log(req.cookies);
res.send(`用户名:${req.cookies.username},地址:${req.cookies.address}`);
});
app.get('/delete', (req, res) => {
res.clearCookie('username');
res.send('cookie删除成功');
});
app.listen(8080);调试时看响应头里的 Set-Cookie,再看后续请求头里的 Cookie。删除 cookie 的原理是重新设置并让过期时间落到过去,浏览器便立即失效。
易错点:改代码后没重启服务;读取用 req.cookies 而不是 res;删除时路径/域名不匹配可能删不掉。
Cookie 的缺点与 Session 的思路
为什么需要 session:cookie 存在浏览器端,有数量和大小限制(转写稿说单站约 50 个、单个约 4KB),每次请求都携带会增加流量,且用户可删改,安全性有限。
怎么想:把主要数据放服务器,浏览器只保存一个唯一标识。服务器为每个会话创建 session 对象和唯一 session ID,再通过 Set-Cookie 把 session ID 存到浏览器;后续请求带上它,服务器据此找到对应 session。
怎么做:session 数据可存内存、文件或数据库;express-session 默认存内存,服务器重启后原 session 丢失,所以演示时重启后要重新设置。
易错点:session 仍要依赖 cookie 保存 session ID;不要以为 session 数据在浏览器里;resave 可理解为每次请求重新保存/延长有效期,转写稿中“receive”应纠正为 resave。
用 express-session 演示
js
const session = require('express-session');
app.use(session({
name: 'sess',
secret: 'keyboard cat',
resave: true,
cookie: { maxAge: 3600 * 1000, httpOnly: true }
}));
app.get('/set', (req, res) => {
req.session.username = '告料纯糖';
req.session.userId = '1001';
req.session.parents = 1;
res.send('session设置成功');
});
app.get('/get', (req, res) => {
res.send(`用户名:${req.session.username},用户ID:${req.session.userId}`);
});
app.get('/delete', (req, res) => {
delete req.session.userId;
res.send('删除单个session成功');
});
app.get('/destroy', (req, res) => {
req.session.destroy(() => res.send('全部session删除成功'));
});调试时观察:设置后响应头出现 Set-Cookie,值很长,是加密后的 session ID;请求 /get 时请求头自动带 cookie,服务器据此取到 req.session。删除单个属性用 delete req.session.userId,销毁当前客户端会话用 req.session.destroy。
易错点:httpOnly: true 时前端 JS 读不到该 cookie;maxAge 单位仍是毫秒;服务器重启会丢内存 session,需重新 /set。
本节回顾的边界说明
先说明一个关键点:本节笔记的回顾清单是 MongoDB 安装启动、数据库/集合/文档、mongo 命令、JS 使用 mongoose 操作 MongoDB;但提供的转写稿实际讲的是 cookie/session 会话控制,与本节笔记主题不一致。因此下面只依据笔记中的回顾清单扩写,不把 cookie/session 的推导硬套到 MongoDB 上,避免编造。原笔记清单保留如下:
text
1. MongoDB 安装启动
数据库 集合 文档
2. mongo 命令向MongoDB服务发送操作指令
3. JS 使用 mongoose 向MongoDB服务发送操作指令MongoDB 安装与启动:先让服务跑起来
为什么需要:MongoDB 不是一段只在前端运行的代码,而是一个需要先启动的数据库服务。后面的 mongo 命令、mongoose 连接,本质上都是客户端在向这个服务发送操作指令。服务没起来,后面所有连接都会失败。
怎么想:把 MongoDB 分成“服务端”和“客户端”两层。服务端负责真正存储数据、监听端口;客户端可以是 mongo shell,也可以是 Node.js 里的 mongoose。学习顺序应是:先启动服务,再连接服务,最后发指令。
怎么做:安装 MongoDB 后启动数据库服务,确认服务监听正常;再用 mongo/mongosh 这类命令行客户端连接。具体命令和端口以实际安装版本为准,不要死记某个版本。连接成功后再进入数据库操作。
易错点:服务未启动就连接;端口被占用或连接地址写错;把“安装完成”误认为“服务已启动”;不同版本客户端命令不同却混用。调试时先看服务是否运行,再看连接字符串。
数据库、集合、文档:先建立数据层级
为什么需要:MongoDB 是文档型数据库,如果不先理解层级,就容易把关系型数据库的表、行概念直接套过来,导致建模混乱。
怎么想:可以按“数据库 → 集合 → 文档”理解。数据库是最大的数据容器;集合类似一组文档的容器;文档是具体的一条数据,通常以类似 JSON 的 BSON 结构保存。一个数据库里可以有多个集合,一个集合里有多条文档。
怎么做:先确定业务用哪个数据库,再确定数据放在哪个集合,最后设计文档字段。例如用户数据放用户集合,每条用户记录就是一个文档。字段设计要围绕查询和写入需求。
易错点:把集合当成“表”后强行要求固定列;文档字段随意增删导致结构不一致;数据库名、集合名拼写错误;以为集合必须先严格建表。MongoDB 灵活不等于可以乱,仍要约定字段结构。
用 mongo 命令向服务发送操作指令
为什么需要:命令行客户端是最直接验证数据库服务是否正常、数据是否写入成功的方式。它能把“连接、选库、查集合、增删改查”拆开看清楚。
怎么想:mongo 命令不是数据库本身,而是客户端工具。你输入命令,它把操作发给 MongoDB 服务,服务执行后返回结果。学习时应先验证连接,再选数据库,再操作集合。
怎么做:连接服务后,切换到目标数据库,查看集合,执行插入和查询,确认数据存在。调试时先做最小插入,再做查询;如果查不到,检查是否选错数据库、集合名是否一致。
易错点:连接后没切数据库就操作;数据库名和集合名大小写或拼写不一致;插入后没查询验证;把命令行结果当成前端页面结果。排错顺序应是:服务 → 连接 → 数据库 → 集合 → 文档。
用 JS + mongoose 向 MongoDB 服务发送操作指令
为什么需要:实际 Node.js 项目不会总靠命令行操作数据库,而是需要在代码里连接、定义数据结构、执行增删改查。mongoose 就是在 JS 中操作 MongoDB 的常用工具。
怎么想:mongoose 仍然是客户端,它最终也是向 MongoDB 服务发指令。代码层通常分三步:连接数据库;定义 Schema/Model 描述文档结构;通过 Model 调用查询、创建、更新、删除方法。
怎么做:先写连接字符串并连接;再定义模型;最后在接口或脚本中调用模型方法。调试时先确认连接成功,再做一次写入和查询。若查询为空,检查连接的是不是同一个数据库、模型对应集合是否正确、查询条件是否匹配。
易错点:服务没启动就连接;连接字符串中的数据库名写错;模型名与集合名对应关系不清;把 Schema 当成数据库本身;异步操作未等待结果就返回;命令行写入和代码连接的不是同一个库。记住:mongo 命令和 mongoose 只是两种客户端,核心都是向同一个 MongoDB 服务发送操作指令。
本节易错点汇总
本节的主线不是“学几个命令”,而是建立一条链路:MongoDB 服务启动 → 数据库/集合/文档分层 → mongo 命令验证 → mongoose 在 JS 中操作。排错时不要一上来改代码,先确认服务是否运行、连接地址和数据库名是否一致,再确认集合和文档结构。只要这条链路清楚,命令行和 mongoose 的用法就只是同一原理的两种入口。
会话控制:无状态 HTTP 下的登录问题
为什么需要:HTTP 是无状态协议,服务器无法区分多次请求是否来自同一客户端。用户第一次请求登录了,下一次请求时服务器并不知道他登录过,登录就失去意义。
怎么想:站在后端角度,请求来自一个个浏览器;它不关心操作者是人还是别的,只关心“这个浏览器之前来过没有”。因此需要额外机制记住登录状态。
怎么做:引入会话控制,常见方案有 cookie、session、token。
易错点:无状态不等于不能登录,而是要靠会话控制补状态;会话控制主要在后端实现,前端负责配合。
常见方案与 token 的定位
为什么需要:cookie、session 都依赖浏览器,但前端开发还包括原生 iOS/Android、React Native、小程序等脱离浏览器的场景。
怎么想:token 不是 HTTP 协议自带的,而是开发者设计的机制,原理与 cookie/session 相似,但不完全依赖浏览器。
怎么做:浏览器场景常用 cookie/session;跨端或脱离浏览器时考虑 token。
易错点:不要以为 token 是 HTTP 协议规定;也不要以为前端只写页面就不用懂会话控制,实际开发必须按后端要求配合。
cookie:把状态记在浏览器
为什么需要:让浏览器记住登录状态,下次请求自动带上,后端据此判断是否登录过。
怎么想:设置与否由服务器决定,真正保存和执行的是浏览器。服务器通过响应头告诉浏览器怎么设置 cookie。
怎么做:登录成功后,服务器在响应头中返回 Set-Cookie;浏览器保存后,后续请求把 cookie 放进请求头 Cookie;后端从请求头读取。演示中可用 cookie-parser:
js
app.use(cookieParser());
res.cookie('username', 'admin', { maxAge: 3600 * 1000 });
res.cookie('userId', '1001');
// 读取
req.cookies易错点:cookie 按域名隔离,127.0.0.1 设置的 cookie,换成 localhost 通常拿不到;换浏览器也不共享;同一浏览器同一网站只能存一套 cookie。默认 cookie 浏览器关闭即失效;maxAge 单位是毫秒,但响应头里常显示为秒,且 Expires 是零时区时间,别误判。删除 cookie 的原理是重新设置并让过期时间变成过去时间,浏览器会立即删掉。
调试与验证:从响应头到请求头
为什么需要:确认 cookie 到底有没有设置、有没有随请求携带。
怎么想:设置看响应头 Set-Cookie,存储看浏览器“应用”面板,携带看网络请求的请求头 Cookie。
怎么做:F12 打开“应用”查看 cookie;刷新页面看响应标头;清空 cookie 后刷新,登录态丢失;换域名验证隔离;关闭整个浏览器验证会话 cookie 失效。
易错点:只关标签页不等于关浏览器;清缓存要勾选 Cookie;改代码后要重启服务,否则响应头不会变化;删除某个 cookie 后,同网站其他路径也读不到它。
cookie 的缺点
为什么需要:理解为什么还要引入 session。
怎么想:cookie 存在客户端,有数量和大小限制;每次请求都携带,增加流量;用户还能删改。
怎么做:cookie 只存少量、非敏感信息,如用户名或标识。
易错点:一般每网站约 50 个、单个约 4KB;不要把敏感信息放 cookie;用户删了就重新登录,不能把 cookie 当唯一安全凭据。
session:数据在服务器,cookie 只存 ID
为什么需要:解决 cookie 容量、流量和客户端可改的问题。
怎么想:把主要数据放服务器,为每个浏览器创建 session 对象和唯一 session ID;浏览器只保存这个 ID。
怎么做:登录验证通过后把用户信息写入 req.session;服务器通过响应头让浏览器保存 session ID;后续请求带 cookie,服务端按 ID 找到对应 session。演示中可用 express-session:
js
app.use(session({
name: 'session',
secret: '...',
resave: true,
saveUninitialized: false,
cookie: { maxAge: 3600 * 1000, httpOnly: true }
}));
req.session.username = '张三';
req.session.userId = '1001';
// 读取
req.session.username;
// 删除单个
delete req.session.userId;
// 删除当前客户端全部
req.session.destroy(() => {});易错点:session 可存内存、文件或 MongoDB,默认内存,服务重启会丢失;session ID 要加密签名(加盐);resave 可让活跃请求重新计时,saveUninitialized 一般设 false;destroy 只删当前客户端;session 依赖 cookie 传 ID,cookie 丢了就找不到;换域名或浏览器同样隔离。
课堂画面






代码示例
示例一:Express + cookie-parser 实现 cookie 的设置、读取、删除
js
// cookie-demo/index.js
// 安装:npm i express cookie-parser
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
// 1. 中间件:解析请求头里的 Cookie -> req.cookies
// 同时给响应对象加上 res.cookie / res.clearCookie 方法
app.use(cookieParser());
// 静态页面(把示例三的 index.html 放到 public 目录即可同源访问)
app.use(express.static('public'));
// 2. 设置 cookie
app.get('/set', (req, res) => {
// res.cookie(名字, 值, 配置对象) ==> 最终写进响应头 Set-Cookie
res.cookie('username', 'admin');
res.cookie('userId', '1001');
res.cookie('address', '北京', {
maxAge: 3600 * 1000, // 单位是毫秒,这里是 1 小时
httpOnly: true, // 前端 JS 读不到这个 cookie
path: '/' // 默认就是 /,整个网站都能带
});
res.send('cookie 设置成功');
});
// 3. 读取 cookie —— 用请求对象 req 取,不是 res
app.get('/get', (req, res) => {
console.log('req.cookies =', req.cookies);
res.send(`用户名:${req.cookies.username},地址:${req.cookies.address}`);
});
// 4. 删除 cookie
app.get('/delete', (req, res) => {
// 原理:重新下发一次同名 cookie,把 expires 设成 1970-01-01
res.clearCookie('username');
res.send('cookie 删除成功');
});
app.listen(8080, () => {
console.log('服务已启动:http://127.0.0.1:8080');
});关键行与易错点
app.use(cookieParser())必须写在所有路由之前,否则req.cookies是undefined,res.cookie也不存在。- 设置 cookie 是后端决定、浏览器执行:后端只是往响应头写
Set-Cookie,浏览器收到后才真正存到本地。 - 读取 cookie 用请求对象
req.cookies(数据在请求头里随请求带过来),不是响应对象。 maxAge单位是毫秒,而浏览器 DevTools 的 Application 面板里显示的是秒;不写maxAge就是会话级 cookie,浏览器一关就没了。httpOnly: true后,浏览器里document.cookie读不到它,但请求时浏览器照样自动带上。- 删除 cookie 的本质是把过期时间改成 1970 年,不是真的“从磁盘删掉”。
- 域名限制:用
127.0.0.1设置的 cookie,换成localhost访问取不到,哪怕两者指向同一台服务器。 - 中文、数组等值会被编码,DevTools 里看到的是编码后的字符串,别以为是乱码出错。
示例二:Express + express-session 实现 session 的设置、读取、删除
js
// session-demo/index.js
// 安装:npm i express express-session
const express = require('express');
const session = require('express-session');
const app = express();
// 1. session 中间件(必须放在路由之前)
app.use(session({
name: 'sid', // 浏览器 cookie 里存 sessionID 的键名,默认 connect.sid
secret: 'keyboard cat', // 签名(加盐)密钥,防止前端伪造 sessionID
resave: true, // 每次请求都重新保存 session -> 重新计时
saveUninitialized: false, // 没有内容时不创建 session
cookie: {
maxAge: 3600 * 1000, // cookie 有效期,毫秒,1 小时
httpOnly: true // 前端 document.cookie 读不到 sessionID
}
}));
// 2. 设置 session:给 req.session 这个对象加属性即可
app.get('/set', (req, res) => {
req.session.username = '张三';
req.session.userId = '1001';
req.session.address = '北京';
res.send('session 设置成功');
});
// 3. 读取 session
app.get('/get', (req, res) => {
console.log(req.session);
res.send(`用户名:${req.session.username},用户ID:${req.session.userId}`);
});
// 4. 删除单个属性
app.get('/delete', (req, res) => {
delete req.session.userId;
res.send('session 删除成功');
});
// 5. 删除整个 session(只删当前这个浏览器的)
app.get('/destroy', (req, res) => {
req.session.destroy(err => {
if (err) return res.send('销毁失败');
res.send('session 全部删除');
});
});
app.listen(8080, () => {
console.log('服务已启动:http://127.0.0.1:8080');
});关键行与易错点
express-session自动做两件事:服务端建 session 对象并生成唯一sessionID;响应头里Set-Cookie只存这个 ID(还是加密签名后的),大量数据留在服务端。secret必填,用于签名(加盐);没有它前端就能伪造sessionID,安全性直接归零。resave: true就是“重新计时”:只要用户还在请求,有效期就往后顺延;长时间不请求才会失效。req.session本身就是一个对象,赋值即保存,delete req.session.xxx删单个属性,req.session.destroy()删整个。- 默认 session 存在内存里:后端服务一重启,session 全部丢失;此时浏览器里的 cookie 还在,但服务端找不到对应记录,等于未登录——这是最容易“以为自己写错了”的坑。
- 修改代码后
nodemon自动重启,等于 session 被清空,必须重新请求/set再/get。 cookie.maxAge和上一节一样是毫秒;httpOnly: true让前端 JS 拿不到 sessionID,这是常规做法。
示例三:前端页面观察 cookie 的读写(配合示例一)
html
<!-- cookie-demo/public/index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>cookie / session 前端观察</title>
<style>
body { font-family: sans-serif; padding: 20px; }
button { margin-right: 8px; padding: 6px 14px; cursor: pointer; }
pre { background: #f5f5f5; padding: 12px; border-radius: 6px; min-height: 60px; }
</style>
</head>
<body>
<button data-url="/set">设置</button>
<button data-url="/get">读取</button>
<button data-url="/delete">删除</button>
<pre id="out">点击按钮,同时打开 F12 的 Network 面板看请求头 / 响应头</pre>
<script>
const out = document.getElementById('out');
document.querySelectorAll('button').forEach(btn => {
btn.onclick = async () => {
const res = await fetch(btn.dataset.url); // 同源请求,自动带上 cookie
const text = await res.text();
out.textContent =
'接口返回:' + text + '\n' +
'document.cookie:' + (document.cookie || '(空)');
};
});
</script>
</body>
</html>关键行与易错点
document.cookie只能读到非 httpOnly 的 cookie;address设了httpOnly,所以这里永远看不到它,但 Network 面板的请求头 Cookie 里一定带着它。- 页面必须和后端同源(同协议 + 同域名 + 同端口)才能共用一套 cookie;跨域
fetch需要credentials: 'include'且后端配置 CORS。 - 同一个网站只存“一套” cookie,登录第二个账号会挤掉第一个——想同时登两个账号只能开两个浏览器。
- 验证流程固定是三步:点“设置” → 看 Network 的响应头 Set-Cookie → 点“读取”,看请求头 Cookie 是否带过去。
常见错误
- 现象:调用
res.cookie()报not a function。→ 原因:cookie-parser未安装、未引入,或包名拼成cookie-parser少写r。→ 修法:npm i cookie-parser,const cookieParser = require('cookie-parser'),并在路由前app.use(cookieParser())。 - 现象:
req.cookies是undefined,或读取不到刚设置的 cookie。→ 原因:中间件未注册、注册在路由之后,或读取时误用res.cookies。→ 修法:确保app.use(cookieParser())在所有相关路由之前;读取统一用req.cookies。 - 现象:改了代码后浏览器仍不带 cookie / 看不到新响应头。→ 原因:Node 服务未重启,仍跑旧代码。→ 修法:开发用
nodemon,或每次改完手动重启;排查时先看 Network 的请求头/响应头是否真的变化。 - 现象:
maxAge设成3600,以为是一小时,结果很快失效或时间显示“对不上”。→ 原因:服务端maxAge单位是毫秒;DevTools 里常显示秒/UTC 时间。→ 修法:写3600 * 1000;调试时同时看Expires/Max-Age,不要按本地时区硬猜。 - 现象:
127.0.0.1能拿到登录态,换localhost就没了。→ 原因:cookie 按主机/域名隔离,默认 domain 是设置时的访问主机。→ 修法:开发环境统一入口,固定用同一个 host + port;不要一会儿127.0.0.1一会儿localhost。 - 现象:前端
document.cookie读不到 session cookie。→ 原因:配置了httpOnly: true。→ 修法:登录态通常保持httpOnly: true,前端不要依赖读取;确需前端读取时再显式设为false,并评估 XSS 风险。 - 现象:
express-session设置后能读到,服务重启后登录态全丢。→ 原因:默认MemoryStore存在内存中,重启即清空;也可能只访问了读取路由,没先执行写入 session 的路由。→ 修法:开发阶段接受重启失效,先访问写入路由再测读取;生产环境换持久化 store。 - 现象:删除 cookie / 注销 session 后仍能读到旧状态。→ 原因:
clearCookie的名称、path、domain与设置时不匹配;或只删了 session 字段,没有真正销毁会话。→ 修法:clearCookie与设置时同名同path/domain;注销用req.session.destroy(cb),删单个字段用delete req.session.xxx。 - 现象:
express-session启动报secret required或配置不生效。→ 原因:初始化配置对象缺secret,或app.use(session(...))写法/位置错误。→ 修法:在路由前注册app.use(session({ secret: '...', ... }));密钥用环境变量管理,不要提交真实密钥。
练习
- 用
express + cookie-parser实现/set-cookie、/get-cookie、/del-cookie三个路由:设置一个有效期 1 小时、httpOnly: true的 cookie,并分别用 DevTools 的 Network 与 Application 验证设置、读取、删除结果。 - 给出一个最小复现:
/get路由里用res.cookies取不到值。请定位问题并改到可运行,要求说明中间件顺序、req/res使用分别错在哪。 - 用
express-session实现/login、/me、/logout:/login写入req.session.user = { id, name },/me读取并返回用户信息,未登录返回 401,/logout销毁会话。要求重启服务前后各测一次并记录差异。 - 做一组对照实验:分别用
127.0.0.1与localhost访问/set-cookie和/get-cookie,记录 cookie 是否共享;再把httpOnly分别设为true/false,观察document.cookie的结果,并写出开发环境统一访问入口的方案。 - 设计一份上线前检查清单:至少覆盖 cookie 的
httpOnly、secure、sameSite、maxAge,session store、secret管理、注销逻辑与域名/路径一致性。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 会话控制介绍 | 06:14 |
| 2 | cookie实现原理 | 16:18 |
| 3 | cookie使用演示 | 37:38 |
| 4 | cookie的缺点 | 02:37 |
| 5 | session介绍 | 05:33 |
| 6 | session实现原理 | 10:04 |
| 7 | session使用演示 | 26:06 |
小结
- 会话控制排错先看“中间件是否注册、是否在路由前”,
cookie-parser和express-session的顺序错误是最常见根因。 - 调 cookie 不要靠猜:同时看 Network 的请求头/响应头和 Application 面板;
maxAge的毫秒单位与 DevTools 显示时区要分清。 - 开发环境必须统一 host + port,混用
127.0.0.1与localhost会制造“登录态莫名丢失”的假故障。 httpOnly应作为登录态 cookie 的安全默认;前端业务不要依赖document.cookie读取登录凭证。express-session默认MemoryStore只适合开发,重启即失效;生产必须换持久化 store 并规范管理secret。- 删除/注销要成对检查名称、
path、domain;注销会话用destroy,删单个字段用delete req.session.xxx。 - 登录态判断以服务端 session/token 校验为准,前端路由守卫只负责体验层,不能替代后端鉴权。
- 上线前按安全清单过一遍:
httpOnly、secure、sameSite、有效期、store、密钥、注销与域名路径一致性。