当前位置: 首页 > news >正文

1.16 Cookie 和 Session

在 Node.js 中,Cookie 和 Session 是实现用户身份验证和状态管理的核心技术。

一、核心概念

1. Cookie
  • 定义:服务器发送到用户浏览器并保存在本地的小段数据。
  • 用途:存储用户信息、跟踪会话、记住登录状态等。
  • 特点
    • 数据存储在客户端。
    • 随每次 HTTP 请求发送到服务器。
    • 有大小限制(通常 4KB)。
    • 可设置过期时间。
2. Session
  • 定义:服务器端存储用户会话数据的机制。
  • 用途:存储敏感信息(如用户 ID、权限),避免客户端篡改。
  • 特点
    • 数据存储在服务器端。
    • 每个会话有唯一的 Session ID(通常存储在 Cookie 中)。
    • 需要配合 Cookie 或 URL 参数使用。

二、Cookie 基础用法

原生 Node.js 处理 Cookie

当你访问一个网站时,服务器可以通过 HTTP 响应头 Set-Cookie 向你的浏览器发送一个或多个 Cookie。浏览器会保存这些 Cookie,并在后续对该域名的请求中通过 Cookie 请求头自动发送回去给服务器。

const http = require('http');const server = http.createServer((req, res) => {// 设置一个名为 'example' 的 Cookieres.setHeader('Set-Cookie', ['example=value']);// 读取 Cookieconst cookies = req.headers.cookie;console.log('Cookies received:', cookies);res.end('Hello World');
});server.listen(3000, () => {console.log('Server running at http://localhost:3000/');
});

 Cookie 的基本组成部分

一个完整的 Cookie 由以下部分组成:

name=value; Path=path; Domain=domain; Expires=date; Max-Age=seconds; HttpOnly; Secure; SameSite=mode

Set-Cookie: name=value; [属性1=值1]; [属性2=值2]; ...
1. 必选部分
  • name=value
    Cookie 的名称和值,必须用 = 连接,且不能包含分号、逗号或空格。
    • 示例
      sessionId=abc123
      username=john_doe
2. 可选属性

Cookie 可以包含多个可选属性,用于控制 Cookie 的行为:

  • Path=/
    指定 Cookie 的路径,限制 Cookie 只在该路径下有效。

    • 示例
      Path=/api → 仅 /api 及其子路径可访问。
  • Domain=example.com
    指定 Cookie 的域名,限制 Cookie 只在该域名及其子域名下有效。

    • 示例
      Domain=.example.com → 对 example.com 和所有子域名有效。
  • Expires=Thu, 01 Jan 2030 00:00:00 GMT
    指定 Cookie 的过期时间,之后 Cookie 将被浏览器删除。

    • 示例
      Expires=Wed, 21 Oct 2025 07:28:00 GMT
  • Max-Age=3600
    指定 Cookie 的有效期(秒),优先于 Expires

    • 示例
      Max-Age=86400 → 有效期 24 小时。
  • HttpOnly
    标记 Cookie 只能通过 HTTP (S) 请求访问,不能被 JavaScript 读取,防止 XSS 攻击。

    • 示例
      HttpOnly
  • Secure
    标记 Cookie 只能通过 HTTPS 协议发送,防止中间人攻击。

    • 示例
      Secure
  • SameSite=Strict|Lax|None
    控制 Cookie 在跨站请求时的行为,防止 CSRF 攻击。

    • 示例
      SameSite=Strict → 仅允许同源请求携带 Cookie。

Cookie 属性详解

1. Path 属性
  • 作用:限制 Cookie 可被访问的路径。
  • 示例
    Set-Cookie: user=john; Path=/admin
    
     
    • 该 Cookie 仅在 /admin 及其子路径(如 /admin/dashboard)中有效。
    • 访问 /home 时不会发送该 Cookie。
2. Domain 属性
  • 作用:指定 Cookie 可被访问的域名。
  • 示例
    Set-Cookie: session=abc; Domain=.example.com
    
     
    • 该 Cookie 对 example.comwww.example.comapi.example.com 等子域名均有效。
    • 若未指定 Domain,则默认为当前域名(不包含子域名)。
3. Expires 和 Max-Age
  • Expires

    • 指定具体的过期日期(GMT 格式)。
    • 示例
      Expires=Sun, 10 Jun 2025 12:00:00 GMT → Cookie 将在该时间过期。
  • Max-Age

    • 指定 Cookie 的有效期(秒)。
    • 示例
      Max-Age=0 → 立即删除 Cookie。
      Max-Age=3600 → 有效期 1 小时。
4. HttpOnly
  • 作用:防止 JavaScript 通过 document.cookie 访问 Cookie,降低 XSS 攻击风险。
  • 示例
    Set-Cookie: token=123; HttpOnly
    
    • 该 Cookie 无法被 JavaScript 读取,只能通过 HTTP 请求发送。
5. Secure
  • 作用:确保 Cookie 仅在 HTTPS 连接中发送,防止中间人攻击。
  • 示例
    Set-Cookie: auth=secret; Secure
    
    • 在 HTTP 连接中,该 Cookie 不会被发送。
6. SameSite
  • 作用:控制 Cookie 在跨站请求时的行为,防止 CSRF 攻击。
  • 取值
    • Strict
      仅允许同源请求携带 Cookie。
      示例:

      Set-Cookie: csrf_token=abc; SameSite=Strict
      
       
      • 从 https://example.com 访问 https://example.com 时发送 Cookie。
      • 从 https://another-site.com 访问 https://example.com 时不发送 Cookie。
    • Lax
      允许部分跨站请求携带 Cookie(主要是安全的 GET 请求)。
      示例:

      Set-Cookie: session=xyz; SameSite=Lax
      
       
      • 从外部网站通过链接访问(GET 请求)时发送 Cookie。
      • 从外部网站通过表单提交(POST 请求)时不发送 Cookie。
    • None
      允许跨站请求携带 Cookie,但必须同时设置 Secure 属性。
      示例:

      Set-Cookie: tracking_id=123; SameSite=None; Secure
      
       
      • 仅在 HTTPS 环境下允许跨站请求携带 Cookie。

 服务器发送 Cookie报文

HTTP/1.1 200 OK
Set-Cookie: sessionId=abc123; Path=/; HttpOnly
Set-Cookie: user=john; Expires=Thu, 01 Jan 2030 00:00:00 GMT; Secure; SameSite=Lax
Content-Type: text/html

客户端发送 Cookie报文

GET /api/data HTTP/1.1
Host: example.com
Cookie: sessionId=abc123; user=john
  1. Cookie 大小限制

    • 大多数浏览器限制单个 Cookie 大小为 4KB。
    • 每个域名的 Cookie 数量限制通常为 50 个左右。
  2. 跨域 Cookie

    • 默认情况下,Cookie 不支持跨域。
    • 可通过 Domain 和 SameSite=None; Secure 实现有限的跨域支持。
  3. 编码问题

    • Cookie 值应使用 encodeURIComponent() 编码,读取时使用 decodeURIComponent() 解码。

 在 Express 中设置 Cookie

需要的中间件

npm install cookie-parser
const express = require('express');
const app = express();const cookieParser = require('cookie-parser');
app.use(cookieParser()); // 解析 Cookie// 设置 Cookie
app.get('/set-cookie', (req, res) => {res.cookie('username', 'john_doe', {maxAge: 3600000,      // 有效期 1 小时(毫秒)httpOnly: true,       // 防止客户端脚本访问secure: process.env.NODE_ENV === 'production', // 仅 HTTPSsameSite: 'strict'    // 防止 CSRF 攻击});res.send('Cookie 已设置');
});// 读取 Cookie
app.get('/get-cookie', (req, res) => {const username = req.cookies.username;res.send(`用户名: ${username}`);
});// 清除 Cookie
app.get('/clear-cookie', (req, res) => {res.clearCookie('username');res.send('Cookie 已清除');
});app.listen(3000);

三、Session 基础用法

在 Node.js 中,没有内置的 Session 模块,测试环境.可以通过组合 HTTP 模块、Cookie 和内存来原生实现 Session 管理。

      用户需要session时.首先解析cookie.如果cookie里包含Session ID.,通过 Session ID 查找对应的数据。如果没有Session ID,生成一个唯一的 Session ID(通常使用 UUID),服务器端维护一个 Session 数据存储,将 Session ID 存储在 Cookie 中,随请求写会客户端

// 内存中的 Session 存储
const sessions = new Map();
const sessionCookieName = 'session_id';const crypto = require('crypto');// 生成随机 Session ID
function generateSessionId() {return crypto.randomBytes(16).toString('hex');
}// 解析 Cookie 字符串
function parseCookies(cookieHeader) {const cookies = {};if (cookieHeader) {cookieHeader.split('; ').forEach(cookie => {const [name, value] = cookie.split('=');cookies[name] = decodeURIComponent(value);});}return cookies;}setInterval(() => {for (const [sessionId, session] of sessions) {if (Date.now() - session.timestamp > 30 * 60 * 1000) {// 清除过期的 Sessionsessions.delete(sessionId);}}}, 30*60*1000); // 每30分钟检查一次session是否过期function destroySession(session_id){sessions.delete(session_id);}module.exports = function(req, res){//用nodejs 解析res带过来的cookieconst cookie = req.headers.cookie;const cookieObj = parseCookies(cookie);const sessionId = cookieObj[sessionCookieName];let timestamp = Date.now();let state = 0; // state =0 刚创建,1,过期,从新创建,2,获取if( sessionId  && sessions.has(sessionId)){let tmpObj = sessions.get(sessionId)if(timestamp - tmpObj["timestamp"] > 30*60*1000){//session过期state = 1;let  obj = {timestamp,state};sessions.set(sessionId,obj);return obj;}tmpObj["state"] = 2;tmpObj["timestamp"] = timestamp;req.destroySession = destroySession.bind(null,sessionId)return tmpObj;}else{const newSessionId = generateSessionId();let obj = {timestamp,state};sessions.set(newSessionId,obj)res.setHeader('Set-Cookie', [sessionCookieName + '=' + newSessionId]);req.destroySession = destroySession.bind(null,newSessionId)return obj;}}

在 Express 中使用 Session

express-session 是 Express.js 的官方会话中间件,用于管理用户会话。它提供了简单易用的 API,支持多种存储后端,是构建 Node.js 会话系统的首选方案。

npm install express-session
const express = require('express');
const session = require('express-session');
const app = express();// 配置 Session
app.use(session({secret: 'your-secret-key', // 用于签名 Session IDresave: false,             // 不强制保存未修改的 SessionsaveUninitialized: true,   // 保存新创建但未修改的 Sessioncookie: {maxAge: 3600000,         // 有效期 1 小时httpOnly: true,secure: process.env.NODE_ENV === 'production'}
}));// 使用 Session
app.get('/login', (req, res) => {// 模拟登录req.session.user = { id: 1, name: 'John' };req.session.isLoggedIn = true;res.send('登录成功');
});app.get('/profile', (req, res) => {if (req.session.isLoggedIn) {res.send(`欢迎 ${req.session.user.name}`);} else {res.status(401).send('未登录');}
});app.get('/logout', (req, res) => {req.session.destroy(err => {if (err) {console.error(err);}res.send('已注销');});
});app.listen(3000);
  1. 工作流程

    • 用户登录时,服务器创建 Session 并生成唯一 Session ID。
    • Session ID 通过 Cookie 发送到客户端。
    • 后续请求中,客户端通过 Cookie 发送 Session ID。
    • 服务器通过 Session ID 查找对应的 Session 数据。

与JWT对比

特性Cookie/SessionJWT
存储位置服务器(Session)+ 客户端(Cookie)客户端全部存储
状态性有状态(服务器存储数据)无状态(数据编码在 Token 中)
安全性较高(敏感数据在服务器)中等(Token 可能被篡改)
跨域支持差(需特殊配置)好(Token 可放在 Header 中)
性能中等(需查询服务)高(无需查询服务器)
失效控制容易(删除 Session)困难(需实现黑名单)

相关文章:

  • Linux进程池详解:从入门到理解
  • 『uniapp』搜索功能+商品列表滚动效果(详细图文注释)
  • 华为OD机试_2025 B卷_数组排列求和(Python,100分)(附详细解题思路)
  • WWDC25中的HDR技术洞察
  • MySQL 锁学习笔记
  • 浏览器拨打电话 nginx代理wss (mod_cti基于FreeSWITCH)
  • 计算机是怎么跑起来的第五章
  • 【医疗电子技术-7.1】动态血压测量技术
  • 人工智能学习18-Pandas-按标签选择
  • 人工智能学习17-Pandas-查看数据
  • 【Linux】Linux多路复用-poll
  • 【LLM Tool Learning】论文分享: Chain-of-Tools
  • 【Python-Day 26】解锁时间魔法:深入解析 time 与 datetime 模块
  • Java-String
  • Python惰性函数与技术总结-由Deepseek产生
  • 【软测】脚本实现 - 网页自动化测试
  • 搜索问答技术概述:基于知识图谱与MRC的创新应用
  • rt-thread的定时器驱动(裸机版本)记录.
  • Ubuntu中Chromium无法使用Fcitx输入中文的问题
  • 设计师灵感仓库!IconViewer 右键一键提取系统图标,PNG 透明背景素材随取随用
  • 专业的魔站建站系统/网络营销和传统营销的区别有哪些
  • 网络视频网站建设多少钱/可以免费投放广告的平台
  • 手机怎么样自己做网站/刷网站排名软件
  • 星辰wordpress/关键词优化公司哪家强
  • python做网站显示表格/网络营销推广专家
  • 网站留言板样式/市场营销方案