- 后端
- 微服务
- 云原生
【免费下载链接】midway
🍔 A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 🌈
本文以@midwayjs/session组件(位于 packages/session)为主体,系统讲解在 Midway(Koa / FaaS)应用中启用与配置 Session 的完整路径:默认配置、可继承的 koa-session 全量参数、以及通过实现抽象类SessionStore接入自定义存储的实战方案。读完本文,你将能够开箱即用地完成用户会话读写、理解底层ctx.session的存取与自动提交机制,并在 Redis、MySQL 等外部存储中落地自己的 Session Store。
组件定位与适用场景
@midwayjs/session是 Midway 官方为@midwayjs/koa与@midwayjs/faas提供的 Session 组件。它的核心职责是:
- 将 Session 能力挂载到请求上下文,提供
ctx.session/ctx.sessionOptions访问入口(见 middleware/session.ts); - 默认使用Cookie 直存模式(Session 数据经 Base64 + JSON 编码写入 Cookie,体积小、免存储依赖);
- 支持通过自定义
SessionStore切换为外部存储模式(数据存放在 Redis、数据库等,Cookie 中只保存一个会话 ID 外键); - 自动监听会话缺失(missed)、过期(expired)、非法(invalid)等事件并输出日志。
组件内部依赖@midwayjs/cookies完成 Cookie 的读写与签名,相关声明可见 package.json。
安装与接入
安装命令:
$ npm i @midwayjs/session --save接入方式分两种框架:
@midwayjs/koa默认已启用该组件,无需额外配置即可使用;@midwayjs/faas需要手动启用,在src/configuration.ts中将其加入imports:
// src/configuration.ts import { join } from 'path'; import * as faas from '@midwayjs/faas'; import * as session from '@midwayjs/session'; @Configuration({ imports: [ faas, session, ], // ... }) export class ContainerLifeCycle implements ILifeCycle {}组件通过 configuration.ts 中的SessionConfiguration完成装配:在onReady阶段读取session配置,若enable为真,则向所有 koa/faas 应用注册SessionMiddleware,并挂载session:missed、session:expired、session:invalid三个事件的日志监听。
默认配置与完整参数说明
在config.*.ts中通过session配置项进行定制。组件的默认配置位于 config/config.default.ts,实际默认值如下:
export const session = { enable: true, maxAge: 24 * 3600 * 1000, // ms,即 1 天 key: 'MW_SESS', httpOnly: true, // sameSite: null, logValue: true, };参数说明:
| 参数 | 默认值 | 说明 |
|---|---|---|
enable | true | 是否启用 Session 中间件,关闭后ctx.session不再注入 |
maxAge | 24 * 3600 * 1000(毫秒) | Session 有效期。注意代码注释中的 Cookie key 默认名与默认配置存在历史差异,实际生效值为MW_SESS(测试 index.test.ts 中同样以MW_SESS断言) |
key | 'MW_SESS' | 存放会话的 Cookie 名 |
httpOnly | true | 禁止客户端 JavaScript 读取 Cookie;若设置为false,中间件会在启动时输出安全警告 |
sameSite | null(不设置) | 默认删除空值;需要时可按koa-session语义显式配置lax/strict/none |
logValue | true | 会话过期/非法时,是否在session:expired/session:invalid日志中打印会话内容 |
可继承的 koa-session 全量选项
README 明确指出“you can use all config from koa-session”,这些选项在 interface.ts 的SessionOptions中有完整类型定义,并在 middleware/session.ts 的formatOpts中被逐一校验、赋默认值。常用项如下:
maxAge:除了毫秒数值,还可设置为'session',表示会话级 Cookie(浏览器/会话关闭即失效);底层在save时会写入_session: true标记并清空maxAge,同时跳过_expire字段(见 lib/context.ts);rolling(默认false):每次响应都强制重写会话 Cookie,重置过期倒计时,适合“持续活跃即续期”的场景;renew(默认false):会话在剩余寿命不足maxAge / 2时自动续期,用于“长期保持登录”;genid:外部存储模式下生成会话 ID 的函数,默认Utils.randomUUID;若配置了prefix则生成prefix + UUID;prefix:外部会话 ID 的统一前缀(genid存在时忽略);externalKey:自定义“外部键”的get/set方法,默认从opts.key对应的 Cookie 中读取;ContextStore:需要从ctx获取依赖的存储类,每个请求执行一次new ContextStore(ctx),需实现get/set/destroy三个实例方法;valid(ctx, session):读取到会话值后、使用前的校验钩子,返回false即触发session:invalid事件并重建会话;beforeSave(ctx, session):会话落盘前的钩子,可在此做数据加工;autoCommit(默认true):请求结束后是否自动提交会话;设为false时需手动调用ctx.session.manuallyCommit();overwrite/signed:Cookie 覆盖写入与签名,默认均为true;encode/decode:自定义 Cookie 内容的编解码函数,默认实现见 lib/util.ts(JSON.stringify后转 Base64,读取时反向解码)。
配置校验逻辑集中在 middleware/session.ts 的
formatOpts:store必须提供get/set/destroy,externalKey必须提供get/set,ContextStore必须是具备上述三方法的类,否则启动时直接断言报错。
使用方式:Cookie Session 模式
在不配置任何 Store 的情况下,Session 数据直接存入MW_SESSCookie(Base64 编码的 JSON)。控制器中读写如下:
import { Controller, Get } from '@midwayjs/core'; @Controller('/') export class HomeController { @Get('/set') async set(ctx) { ctx.session.foo = 'bar'; // 写入会话 return ctx.session; } @Get('/get') async get(ctx) { return ctx.session; // 读取会话(未写数据时不产生 Set-Cookie) } @Get('/remove') async remove(ctx) { ctx.session = null; // 置空即删除会话(响应 204 并清除 Cookie) } }ctx.session对象的能力由 lib/session.ts 中的Session类提供:
ctx.session.key = value写入、直接读取即取值;ctx.session.maxAge = 100:动态修改有效期,修改后会强制落盘(_requireSave = true);ctx.session.regenerate(callback?):重新生成会话(先删除旧会话,再生成新外部键);ctx.session.save(callback?):无论会话是否有数据都强制保存;ctx.session.manuallyCommit():配合autoCommit: false手动提交;session.length/session.populated:判断会话是否已有数据;session.externalKey:仅外部存储模式下存在,返回当前会话的存储键。
底层流程在 lib/context.ts 中:中间件首次访问ctx.session时按需initFromCookie()(解析、valid校验、失败则重建);响应阶段由中间件的finally块调用commit(),通过 lib/util.ts 的 CRC32 哈希对比判断会话是否变更,未变更且未开启rolling/renew时跳过写 Cookie;ctx.session = null则触发remove(),以 1970 年过期时间清除 Cookie。上述行为均有对应测试覆盖,见 test/index.test.ts。
自定义 Session Store:接入外部存储
当会话数据较大或需要跨进程共享(多实例部署、Serverless 场景)时,应切换到外部存储模式。
第一步:继承SessionStore抽象类
在 interface.ts 中定义了抽象类,需要实现三个方法:
import { SessionStore } from '@midwayjs/session'; @Provide() @Scope(ScopeEnum.Singleton) export class MemorySessionStore extends SessionStore { sessions = {}; async get(key) { return this.sessions[key]; } async set(key, value) { this.sessions[key] = value; } async destroy(key) { this.sessions[key] = undefined; } }注意抽象类的方法签名(见 interface.ts):
export abstract class SessionStore { abstract get(key: string); abstract set(key: string, value: string, maxAge: number); abstract destroy(key); }set的第三个参数maxAge用于让 Redis 等支持 TTL 的存储自动过期;底层在落盘时会额外+10000(10 秒)以保证存储先于 Cookie 过期(见 lib/context.ts 的save方法);- 存储中会写入
_expire、_maxAge(或_session)内部字段,读取时由Session构造器还原maxAge; - 实现类需标记为
@Provide()的单例,供容器注入。
第二步:通过SessionStoreManager注入到组件
SessionStoreManager(见 lib/store.ts)是单例管理器,提供setSessionStore/getSessionStore。中间件在resolve阶段会取出管理器中的 Store 并写入sessionConfig.store(见 middleware/session.ts)。接入方式:
import { MemorySessionStore } from './store'; import * as session from '@midwayjs/session'; @Configuration({ imports: [ koa, session, ], //... }) export class AutoConfiguration { @Inject() memoryStore: MemorySessionStore; @Inject() sessionStoreManager: session.SessionStoreManager; async onReady() { this.sessionStoreManager.setSessionStore(this.memoryStore); } }切换到外部存储后,Cookie 中不再保存完整会话数据,而是只保存由genid生成的会话 ID(默认 UUID),会话数据以该 ID 为键写入 Store。仓库中的 memory-session 测试用例 就是这一模式的最小可运行示例。
会话事件与日志排查
ContextSession在会话读取异常时通过emit触发应用级事件(lib/context.ts),组件在 configuration.ts 中统一监听并输出 warn 日志:
session:missed:会话键在存储中不存在;session:expired:_expire早于当前时间,判定过期;session:invalid:valid钩子校验失败。
expired/invalid的日志内容是否打印由logValue配置控制,生产环境若担心敏感信息泄漏可设为false。
总结与选型建议
- 单机、会话数据小:使用默认的 Cookie Session,零配置即可用,注意 Cookie 大小上限(约 4KB);
- 多实例、会话共享、数据量大:实现
SessionStore(如基于ioredis的 Redis Store),配合maxAge的 TTL 参数实现自动过期,并开启rolling或renew控制续期策略; - 安全基线:保持
httpOnly: true,key使用不易猜测的名称,会话写 Cookie 依赖的签名密钥需妥善管理。
本文所涉源码均可从仓库对应路径继续深入阅读:默认配置、选项类型定义、中间件与参数校验、会话上下文管理、会话模型、Store 管理器 以及 功能测试。
- 后端
- 微服务
- 云原生
【免费下载链接】midway
🍔 A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 🌈
相关推荐
Presto Session Properties 完全指南:从 SET SESSION 到源码级调优实践
Presto Session Properties 完全指南:从 SET SESSION 到源码级调优实践 导读 本文以 properties session.
大数据数据库后端RuoYi-Cloud 数据库设计规范
RuoYi Cloud 数据库设计规范 前言 在微服务架构中,良好的数据库设计是系统稳定性和可扩展性的基石。RuoYi Cloud作为基于Spring Clou
认证鉴权后端Yii 2 会话与 Cookie 完全指南:从 $_SESSION 到组件化 Session/Cookie 的实战与源码解析
Yii 2 会话与 Cookie 完全指南:从 $_SESSION 到组件化 Session/Cookie 的实战与源码解析 Sessions(会话)与 Coo
后端Web框架
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考