第17章 会话状态模式

在客户端、服务器内存和数据库之间选择会话状态的权威位置。

学习目标

  • 能为订单向导会话选择客户端、服务器内存或数据库作为状态权威,并说明安全与恢复理由
  • 能用会话键、版本、容量、过期策略和多节点路由记录一次可复核的状态设计
  • 能在正常续期、并发提交、节点故障和过期场景中验证状态一致性,并识别何时撤回

为什么第17章会话状态模式值得单独学习

客户端会话状态减少服务器存储和节点同步,但不能把未经保护的客户端字段当成事实来源。订单折扣、地址和权限等状态必须区分可重建数据与不可由客户端决定的授权事实。

服务器会话状态适合短生命周期、低延迟和可接受丢失的向导,但多节点部署需要粘性路由、复制或明确的故障降级策略。

数据库会话状态提供跨节点恢复和可查询的生命周期,但引入读写延迟、清理任务、容量规划和并发冲突处理。

先建立直觉:状态位置就是责任声明

会话键只负责定位或关联状态,不应直接承载未经签名的权限结论;轮换、撤销和重放防护都要写进设计记录。

过期不是一个孤立的时间常量,而是安全、用户体验、清理成本和恢复目标之间的可验证取舍。

先预测:订单向导在三个节点上运行,用户可以回到上一步修改地址,提交请求可能重试两次。把状态放在客户端、单节点内存还是共享数据库,最先要比较的不是框架偏好,而是会话键可信度、多节点恢复、版本冲突和过期后的补救。

会话状态模式的关键问题是“谁拥有当前事实、谁能修改它、失败后能恢复到什么状态”。状态位置决定数据是否需要签名、请求是否需要路由到同一节点、节点故障是否丢失进度,以及清理任务是否能按租约稳定运行。

目录单元到教学证据

第17章 会话状态模式

第17章 会话状态模式 的单元边界内,学习者要用订单向导会话比较三个目录节点:Client Session State、Server Session State 和 Database Session State。单元键为 poeaa24-chapter-17-session-state-patterns;核心证据是同一应用切片在正常续期、节点切换、并发提交和过期后都能说明状态权威与恢复路径。

评审记录还要回答:会话键如何生成和轮换,客户端字段如何签名或加密,服务器节点如何扩缩容,数据库如何清理过期记录,版本冲突由谁拒绝和重试。如果答案只写“由框架 session middleware 处理”,就无法在架构改变后复核。

专属代码案例:订单向导会话

下面的代码使用共享存储的版本号保护并发更新。它不实现具体数据库,而是让状态权威、版本检查、过期规则和失败信号可观察。

type CheckoutState = {
  address: string;
  updatedAt: number;
  expiresAt: number;
};
 
type SessionRecord = { version: number; state: CheckoutState };
 
class VersionConflict extends Error {}
 
function updateSession(
  record: SessionRecord,
  expectedVersion: number,
  patch: Partial<CheckoutState>,
  now: number,
): SessionRecord {
  if (record.version !== expectedVersion) {
    throw new VersionConflict("session changed");
  }
  if (now >= record.state.expiresAt) {
    throw new Error("session expired");
  }
  return {
    version: record.version + 1,
    state: { ...record.state, ...patch, updatedAt: now },
  };
}

这段代码把四项证据固定下来:状态由共享记录权威持有,客户端必须带预期版本,过期状态不能继续写入,并发更新返回明确冲突而不是静默覆盖。生产实现还需补充会话键轮换、签名或加密、原子写入、清理指标和重试幂等性。

三种状态位置

第17章:会话状态权威位置Client Session State签名 / 大小 / 重放减少服务端存储服务端重算事实Server Session State节点路由 / 内存低延迟访问故障可能丢失Database Session State跨节点 / 持久化版本 / 清理延迟与存储成本同一应用切片:权威、恢复、过期和并发都必须可验证状态位置不是存储细节,而是责任与风险的选择
三种会话状态位置分别把安全、路由或持久化责任推到不同边界,不能只按访问速度选择。

状态位置图把客户端、服务器节点和共享数据库放在同一条请求路径上,帮助评审比较带宽、路由、恢复和一致性责任,而不是只看访问速度。

故障与过期边界

第17章:续期、冲突、故障与过期会话键 + 版本读取权威状态正常续期更新与提交原子版本检查幂等重试写入新版本旧版本冲突拒绝节点故障恢复或安全丢失过期清理提示 / 重启记录版本、原因、用户补救和清理延迟,才能重放失败失败路径必须比成功路径更明确
会话状态设计同时验证续期成功、旧版本冲突、节点故障和过期后的安全恢复。

会话设计必须把正常续期、并发版本冲突、节点故障和过期清理分开验证。无论选择哪个位置,都要给出会话键失效、状态恢复、用户提示和重试的可重放证据。

选择与拒绝矩阵

评审问题选择会话状态位置的证据应拒绝当前方案的信号
权威清楚说明事实由客户端、节点内存或共享存储拥有客户端字段直接决定权限或价格
扩缩容多节点路由、复制或共享恢复策略可测量请求依赖粘性节点却没有故障降级
并发版本、原子写入和重试行为明确重试会静默覆盖其他步骤的更新
过期Expiration Policy 与清理、提示和恢复路径一致过期只删除记录,没有用户可理解的补救
替代已比较三个位置并保留撤回路径只因框架默认 session 存储而选择

常见误区

可验证练习

练习

本组练习围绕 第17章 会话状态模式,要求把状态权威、失败边界和恢复目标写入同一张评审卡。

问题 1:选择位置。 订单向导需要跨三台节点运行,状态包含地址和步骤,不包含不可重建的支付凭据。如何比较三个状态位置?

问题 2:处理并发。 用户在两个浏览器标签页同时修改地址,第二次提交带着旧版本。应该覆盖,还是拒绝?

问题 3:处理过期与故障。 服务器内存会话在节点重启后丢失,且用户已离开两小时。系统应该怎样响应?

名词解释

名词解释

本章出现的专业名词,用大白话再讲一遍。

Client Session State

由客户端携带会话数据、服务端通过签名版本和大小限制进行验证的状态位置。

Server Session State

保存在服务器进程或节点内存中的会话状态,访问快但依赖路由和节点生命周期。

Database Session State

持久化在共享数据库或等价存储中的会话状态,支持跨节点恢复并需要并发与清理策略。

Session Key

标识一次会话的不可猜测令牌,用于定位或验证状态而不是直接承载权限事实。

Expiration Policy

规定会话在不活动、固定时间或业务事件后失效和清理的规则。

本章小结

掌握第17章会话状态模式的标志,不是记住某个 session middleware 的配置,而是能在订单向导中解释“会话键 → 状态权威 → 更新版本 → 节点故障 → 过期恢复”的责任链。客户端、服务器内存和数据库三个位置各有成本,设计必须把安全、扩缩容、并发、清理和用户补救放进同一组可重放证据;当状态权威不清、只依赖粘性路由或过期没有恢复路径时,应拒绝当前方案。

前后导航

来源与改写范围

资料与写作方式声明

本章以Martin Fowler《企业应用架构模式》与公开模式目录权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…