
后端微服务【免费下载链接】hyperf A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.项目地址https://gitcode.com/gh_mirrors/hy/hyperf点击查看免费下载HTTP 是一种无状态协议服务器默认不会保留与客户端交易时的任何状态。要在 Hyperf 项目中实现多个请求之间用户数据的共享最常用的方式就是引入 Session 会话管理组件。本文以官方文档 docs/zh-cn/session.md 为主线结合仓库内 src/session 组件的真实源码与配置完整讲解 Session 的安装、配置、驱动选型、常用 API 以及底层工作原理帮助你在 Hyperf 应用中快速、正确地落地 Session 功能。一、Session 解决什么问题HTTP 请求之间彼此独立服务端无从判断两次请求是否来自同一个用户。Session 的核心思路是在服务端保存一份与用户绑定的数据并通过一个唯一标识Session ID在客户端通常以 Cookie 形式与服务器之间建立关联。此后每个请求带着这个标识到达服务端时服务端就能取出对应的会话数据实现登录状态保持购物车表单回显等跨请求的数据共享。在 Hyperf 中Session 功能由 hyperf/session 组件提供官方文档明确组件当前主要适配了文件和Redis两种存储驱动默认使用文件驱动在生产环境下强烈建议使用Redis驱动因为其性能更好也更符合集群架构下的使用场景。二、安装组件在 Hyperf Skeleton 项目根目录执行以下命令安装 Session 组件composer require hyperf/session安装完成后组件会通过ConfigProvider自动完成相关配置的注册与依赖注入绑定。若需要将默认配置文件发布到项目的config/autoload/目录可执行php bin/hyperf.php vendor:publish hyperf/session发布命令会生成config/autoload/session.php配置文件即 Session 组件的主要配置存放位置。三、配置详解3.1 配置文件结构与默认值发布后的config/autoload/session.php内容与组件内置的 publish/session.php 一致完整结构如下?php use Hyperf\Session\Handler; return [ handler Handler\FileHandler::class, options [ connection default, path BASE_PATH . /runtime/session, gc_maxlifetime 1200, session_name HYPERF_SESSION_ID, domain null, cookie_lifetime 5 * 60 * 60, cookie_same_site lax, ], ];各配置项的含义与默认值整理如下配置项默认值说明handlerHyperf\Session\Handler\FileHandler::classSession 存储驱动的 Handler 类名可改为RedisHandler等options.connectiondefaultRedis 驱动使用的连接名需与 hyperf/redis 组件config/autoload/redis.php中的连接 key 对应options.pathBASE_PATH . /runtime/session文件驱动下 Session 数据文件的存放目录options.gc_maxlifetime1200会话有效期单位秒超期数据将被视为失效options.session_nameHYPERF_SESSION_IDSession Cookie 的名称也是浏览器 Cookie 的 keyoptions.domainnullCookie 的 Domain为null时由中间件取当前请求的 Hostoptions.cookie_lifetime5 * 60 * 60Cookie 的过期时间单位秒默认 5 小时options.cookie_same_sitelaxCookie 的 SameSite 属性用于 CSRF 防护从源码 FileHandlerFactory.php 可以看到gc_maxlifetime直接决定了文件驱动下会话的有效期工厂通过$config-get(session.options.gc_maxlifetime, 1200)读取该值并传入 Handler作为分钟数参与读取校验而 FileHandler.php 的read()方法会使用Carbon::now()-subMinutes($this-minutes)比较文件的最后修改时间超时的 Session 文件将被视为不存在并返回空数据。3.2 配置 Session 中间件Session 组件必须通过中间件介入请求流程才能完成 Session 的启动、读写、保存与 Cookie 下发。因此需要将Hyperf\Session\Middleware\SessionMiddleware注册为 HTTP Server 的全局中间件配置文件config/autoload/middlewares.php示例如下?php return [ // 这里的 http 对应默认的 server name如您需要在其它 server 上使用 Session需要对应的配置全局中间件 http [ \Hyperf\Session\Middleware\SessionMiddleware::class, ], ];注意如果您的应用启用了多个 Server如同时监听http与tcp需要在每个需要使用 Session 的 Server 对应的 server name 下分别配置该中间件。中间件的执行逻辑在 SessionMiddleware.php 中清晰可见先通过$this-config-has(session.handler)判断 Session 是否已配置未配置则直接放行isSessionAvailable()调用SessionManager::start($request)启动会话解析请求 Cookie 中的 Session ID并加载历史数据执行后续请求处理链在finally块中调用SessionManager::end($session)内部执行save()持久化通过addCookieToResponse()将 Session Cookie 写入响应。其中storeCurrentUrl()会在 GET 请求时把当前完整 URL 记录到 Session 中供previousUrl()读取Cookie 的secure属性会根据请求是否为 HTTPS 自动判定httpOnly固定为trueSameSite则取自配置项options.cookie_same_site。3.3 使用文件存储驱动文件存储驱动是默认驱动配置方式为将handler设置为Hyperf\Session\Handler\FileHandler?php use Hyperf\Session\Handler; return [ handler Handler\FileHandler::class, options [ path BASE_PATH . /runtime/session, gc_maxlifetime 1200, ], ];options.path所有 Session 数据文件都会被生成并存储在该目录下默认是根目录下的runtime/session文件夹从源码看FileHandler.php 在构造时会自动检查目录是否存在不存在则通过 Filesystem 以0755权限递归创建每个会话对应一个以 Session ID 命名的文件文件内容为 PHPserialize()序列化后的会话数据gc()清理过期文件时使用 Symfony Finder 按文件修改时间过滤删除超过gc_maxlifetime秒的会话文件。3.4 使用 Redis 存储驱动使用 Redis 驱动前需要先安装 hyperf/redis 组件composer require hyperf/redis然后将handler改为Hyperf\Session\Handler\RedisHandler并通过options.connection指定要使用的 Redis 连接该值与config/autoload/redis.php配置中的 key 命名匹配?php use Hyperf\Session\Handler; return [ handler Handler\RedisHandler::class, options [ connection default, gc_maxlifetime 1200, ], ];从源码 RedisHandlerFactory.php 可以看到工厂会从容器中获取Hyperf\Redis\RedisFactory再调用$redisFactory-get($connection)得到指定连接连同gc_maxlifetime一起构造RedisHandler。RedisHandler.php 的实现非常简洁高效read($id)执行redis-get($id)取不到返回空字符串write($id, $data)执行redis-setEx($id, $this-gcMaxLifeTime, $data)即写入的同时以gc_maxlifetime为过期时间天然实现会话过期无需额外的 GC 清理gc()直接返回 0destroy($id)执行redis-del($id)删除会话构造函数还会校验传入的 Redis 客户端必须是Redis、RedisArray、RedisCluster、Predis\Client或Hyperf\Redis\Redis之一否则抛出InvalidArgumentException。由于数据统一存储在 Redis 中、不依赖单机文件系统因此多节点部署时可以共享同一份会话数据这正是文档建议生产环境优先使用 Redis 驱动的原因。补充从当前仓库源码结构看src/session/src/Handler 目录下还提供了DatabaseHandler数据库存储驱动配合 Hyperf 数据库组件使用与NullHandler空实现常用于测试等 Handler 实现以及与之对应的*Factory工厂类。若需要自定义驱动实现SessionHandlerInterface并提供工厂类、修改handler配置即可。四、Session 的基本使用4.1 获得 Session 对象在控制器或其他由容器管理的类中通过属性注入Hyperf\Contract\SessionInterface即可获得 Session 对象直接调用接口定义的方法?php namespace App\Controller; use Hyperf\Di\Annotation\Inject; use Hyperf\Contract\SessionInterface; class IndexController { #[Inject] private SessionInterface $session; public function index() { // 直接通过 $this-session 来使用 } }SessionInterface定义在 src/contract/src/SessionInterface.php是 Hyperf 对 Session 能力的统一抽象默认由 Session.php 实现。需要说明的是Session 对象是每个请求一个实例的数据类源码注释明确要求每次请求创建新实例由SessionManager在中间件中创建并放入协程上下文Context请求内随处可注入使用。4.2 储存数据使用set(string $name, $value): void方法储存数据?php $this-session-set(foo, bar);从 Session.php 的实现看set()内部通过data_set()写入$attributes数组因此支持点号嵌套路径例如$this-session-set(user.name, hyperf)会写入到[user [name hyperf]]结构中。若需一次性写入多个键值对可使用put($key, $value null)传入数组时批量写入?php $this-session-put([foo bar, user [id 1]]);4.3 获取数据使用get(string $name, $default null)获取数据支持点号路径未命中时返回传入的默认值默认为null?php $this-session-get(foo, $default null);一次性获取所有已储存数据使用all(): array?php $data $this-session-all();all()返回的是整个$attributes数组即当前会话全部数据的快照。4.4 判断 Session 中是否存在某个值使用has(string $name): bool判断某个值是否存在。只要该值存在且不为nullhas方法就会返回true?php if ($this-session-has(foo)) { // }4.5 获取并删除一条数据使用remove(string $name)一步完成获取并删除?php $data $this-session-remove(foo);该方法返回被移除的值若不存在则返回null。源码中通过Arr::pull($this-attributes, $name)实现。4.6 删除一条或多条数据使用forget(string|array $name): void删除数据传入字符串表示删除一条传入 key 字符串数组表示删除多条?php $this-session-forget(foo); $this-session-forget([foo, bar]);4.7 清空当前 Session 数据使用clear(): void清空当前 Session 里的所有数据?php $this-session-clear();注意clear()只清空内存中的属性数组下一次save()时会以空数组覆盖存储层数据如果需要清空并重新生成会话 ID、同时删除旧会话应使用invalidate()详见下文。4.8 获取当前的 Session ID当需要拿 Session ID 自行处理一些逻辑时使用getId(): string?php $sessionId $this-session-getId();Session ID 由Session构造时生成generateSessionId()使用Str::random(40)生成 40 位随机字符串且isValidId()要求 ID 必须为 40 位字母数字ctype_alnum校验相关逻辑在 Session.php 与 SessionManagerTest.php 中均有覆盖。五、接口提供的更多能力源码级扩充除文档列出的基础方法外SessionInterface与Session实现还提供了若干常用能力在实战中同样高频出现方法签名说明replacereplace(array $attributes): void用新数据整体合并覆盖现有属性migratemigrate(bool $destroy false, ?int $lifetime null): bool迁移会话到新的 Session ID保持数据不变$destroy true时先销毁旧会话invalidateinvalidate(?int $lifetime null): bool注销当前会话先clear()清空数据再migrate(true)销毁旧会话并生成新 ID常用于登出逻辑savesave(): void强制保存并关闭会话正常情况下请求结束由中间件自动调用isStartedisStarted(): bool判断会话是否已启动token/regenerateTokentoken(): string/regenerateToken(): string读取/重新生成 CSRF Token存于_token键previousUrl/setPreviousUrlpreviousUrl(): ?string/setPreviousUrl(string $url): void读取/写入上一页 URL中间件会自动为 GET 请求记录pushpush(string $key, $value): void向 Session 中的某个数组键追加一个值此外Session类通过use FlashTrait见 FlashTrait.php还内置了Flash 一次性数据机制常用于表单校验错误提示这类只在下一个请求有效的场景flash($key, $value true)写入数据并标记为新 Flash 数据下次请求后自动过期now($key, $value)写入仅对当前请求有效的 Flash 数据reflash()将所有 Flash 数据保留到下一个请求keep($keys null)仅保留指定的 Flash 键flashInput(array $value)将输入数据如表单旧值写入_old_input配合校验失败回显使用。数据在save()时通过ageFlashData()完成新旧 Flash 数据轮转旧的过期、新的转旧这是 Flash 机制能自动失效的核心。六、底层原理一次请求的完整会话流程结合 SessionManager.php、SessionMiddleware.php 与 Session.php一次带 Session 的 HTTP 请求大致经历以下流程启动中间件调用SessionManager::start($request)。SessionManager通过parseSessionId()遍历请求 Cookie查找名为session_name默认HYPERF_SESSION_ID的 Cookie 值作为 Session ID未找到时构造一个全新 ID。构建 HandlerbuildSessionHandler()读取session.handler配置并从容器解析对应 Handler 实例若配置非法会抛出InvalidArgumentException。加载数据Session::start()内部调用loadSession()通过readFromHandler()从 Handler 读取序列化数据并unserialize()还原为属性数组。业务处理请求进入控制器等业务代码开发者通过注入的SessionInterface读写会话数据。保存请求处理完毕后中间件finally中调用SessionManager::end($session)即save()将serialize($this-attributes)后的数据交给 Handler 的write()持久化Redis 驱动同时设置过期时间。下发 CookieaddCookieToResponse()构造Cookie对象写入响应Cookie 的过期时间由options.cookie_lifetime默认 5 小时或options.expire_on_close决定。由于中间件基于 PSR-15 规范实现且 Session 实例存放在协程上下文中在 Hyperf 的常驻内存 协程模型下每个请求都能获得独立、隔离的会话实例互不串扰。七、测试与验证仓库内 src/session/tests 提供了完整的单元测试可作为理解组件行为与自定义 Handler 时的参考范本SessionTest.php覆盖 Session 对象的创建、ID 校验、属性读写set/get/has/remove/put/forget/clear/replace等核心 APIFileHandlerTest.php验证文件驱动的写入、读取与过期清理SessionManagerTest.php验证会话名获取、Session ID 解析与 Handler 构建SessionMiddlewareTest.php验证中间件的启动、Cookie 下发与请求放行逻辑。例如SessionTest中通过Str::random(40)构造 ID 后断言isValidId()返回true并逐一验证各种数据类型的存取一致性与本文前述 API 行为完全对应。八、生产实践建议驱动选型单机开发调试可用默认文件驱动多实例部署或对性能有要求的场景务必切换到Redis驱动并确保options.connection指向正确的 Redis 连接。过期时间gc_maxlifetime存储层过期与cookie_lifetimeCookie 过期是两个独立概念建议根据业务登录态时长统一规划避免出现Cookie 还在、服务端数据已过期的不一致体验。安全属性默认 Cookie 已开启httpOnlyHTTPS 下自动开启securecookie_same_site默认lax可有效缓解 CSRF 风险。如需跨子域共享会话可配置options.domain。登出实现登出时建议调用invalidate()而非仅clear()以便同时销毁服务端旧会话并重新生成 ID降低会话固定Session Fixation风险。自定义驱动如需接入其他存储如内存表、第三方缓存实现SessionHandlerInterface并提供对应的工厂类、修改handler配置即可组件其余流程无需改动。赞分享后端微服务【免费下载链接】hyperf A coroutine framework that focuses on hyperspeed and flexibility. Building microservice or middleware with ease.项目地址https://gitcode.com/gh_mirrors/hy/hyperf点击查看免费下载相关推荐Hyperf Session 会话管理完全指南从中间件配置到多驱动存储实战Hyperf Session 会话管理完全指南从中间件配置到多驱动存储实战 HTTP 是一种无状态协议服务器不保留与客户端交易时的任何状态因此开发 HTT后端Web框架微服务RPC框架异步编程Hyperf Session 会话管理实战指南文件与 Redis 双驱动、中间件配置与 API 全解析Hyperf Session 会话管理实战指南文件与 Redis 双驱动、中间件配置与 API 全解析 HTTP 是一种无状态协议服务器不会保留与客户端交易后端微服务Hyperf 会话管理Session实战指南安装、配置、存储驱动与完整 API 使用Hyperf 会话管理Session实战指南安装、配置、存储驱动与完整 API 使用 HTTP 协议本身是无状态的服务端无法天然地在多次请求之间保留用户后端Web框架微服务RPC框架异步编程上一篇llamafile 家族新成员 transcribefile单文件、跨平台的语音转文字 CLI 完全指南下一篇OSS-Fuzz base-builder-jvm 镜像深度解析基于 JDK Jazzer 构建 JVM 模糊测试基础环境创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考