【基于 Swoole+Hyperf 的微服务实战】 第二周·周二:Hyperf 的中间件
今天主题是 Hyperf 的中间件。中间件是请求生命周期中的“关卡”可以在请求到达控制器之前或之后执行逻辑如权限校验、日志、跨域处理、参数加解密等。今天我们将亲手构建一个完整的 API 保护体系并用有趣而实用的示例让你彻底掌握中间件。今日目标理解 Hyperf 中间件的核心概念与三种级别全局、路由级、注解级。编写一个Token 校验中间件保护/api/*路由未授权返回 401。实现一个跨域中间件解决前后端分离开发中的 CORS 问题。进阶编写一个参数加解密中间件自动解密请求体、加密响应体。学会使用 Postman 或 curl 对中间件进行全流程测试并理解中间件执行顺序。一、环境准备约 20 分钟我们继续使用hyperf-app项目进入 Docker 容器并开启热重启cdswoole-coursedocker-composeexecswoolebashcd/var/www/hyperf-app# 启动热重启模式方便后续开发php bin/hyperf.php server:watch后续修改代码会自动重启 Worker无需手动操作。二、知识核心Hyperf 中间件机制约 1 小时1. 中间件在生命周期中的位置回顾请求生命周期Request → 全局中间件 → 路由匹配 → 路由中间件 → 控制器 → 响应。中间件可以在控制器前后执行甚至可以提前拦截请求并返回响应阻止后续流程。2. 三种级别的中间件类型作用范围定义方式使用场景全局中间件所有请求在config/autoload/middlewares.php中注册CORS、日志记录、统计路由中间件特定路由或路由组在config/routes.php中通过addMiddleware()绑定权限校验、角色控制注解中间件单个控制器或方法通过#[Middleware]注解应用细粒度控制如限流3. 中间件的实现规范所有中间件必须实现Psr\Http\Server\MiddlewareInterface包含process方法publicfunctionprocess(ServerRequestInterface$request,RequestHandlerInterface$handler):ResponseInterface{// 前置逻辑可以修改 $request或直接返回响应跳过后续$response$handler-handle($request);// 调用下一个中间件或控制器// 后置逻辑可以修改 $responsereturn$response;}关键点$handler-handle($request)是执行链的下一个节点如果不调用后续中间件和控制器都不会执行。三、实战构建 API 保护体系约 2.5 小时项目准备创建需要保护的 API为了演示我们在app/Controller/下创建一个ApiController.php模拟一些 API 接口?phpnamespaceApp\Controller;useHyperf\HttpServer\Annotation\Controller;useHyperf\HttpServer\Annotation\RequestMapping;#[Controller(prefix:/api)]classApiControllerextendsAbstractController{#[RequestMapping(path:user,methods:get)]publicfunctionuser(){return[id1,nameSwoole];}#[RequestMapping(path:secret,methods:post)]publicfunctionsecret(){return[datatop secret info];}}目标让/api/*只有携带合法 Token 的请求才能访问。实战 1Token 校验中间件路由中间件第一步创建中间件类新建app/Middleware/ApiTokenMiddleware.php?phpnamespaceApp\Middleware;usePsr\Http\Message\ResponseInterface;usePsr\Http\Message\ServerRequestInterface;usePsr\Http\Server\MiddlewareInterface;usePsr\Http\Server\RequestHandlerInterface;useHyperf\HttpServer\Contract\ResponseInterfaceasHttpResponse;classApiTokenMiddlewareimplementsMiddlewareInterface{publicfunctionprocess(ServerRequestInterface$request,RequestHandlerInterface$handler):ResponseInterface{// 从 Header 中获取 Token$token$request-getHeaderLine(Authorization);// 模拟校验有效的 Token 为 Bearer secret-api-tokenif($token!Bearer secret-api-token){// 返回 401 响应使用 Hyperf 的 Response 工厂$response\Hyperf\Utils\ApplicationContext::getContainer()-get(HttpResponse::class);return$response-json([code401,messageUnauthorized: Invalid or missing token.])-withStatus(401);}// Token 合法将用户信息写入请求属性方便控制器获取$request$request-withAttribute(user_id,123);// 放行到下一个处理程序return$handler-handle($request);}}第二步将中间件绑定到/api路由组打开config/routes.php添加路由组并应用中间件?phpuseHyperf\HttpServer\Router\Router;// 定义 /api 前缀的路由组所有在此组内的路由都会经过 ApiTokenMiddlewareRouter::addGroup(/api,function(){Router::get(/user,[App\Controller\ApiController::class,user]);Router::post(/secret,[App\Controller\ApiController::class,secret]);},[middleware[App\Middleware\ApiTokenMiddleware::class]]);说明addGroup的第三个参数可以传递中间件数组。你也可以在单个路由上用Router::get(...)-middleware(...)方式绑定。测试无 Token 访问curlhttp://localhost:9501/api/user返回{code:401,message:Unauthorized: Invalid or missing token.}状态码 401。携带合法 Tokencurl-HAuthorization: Bearer secret-api-tokenhttp://localhost:9501/api/user正常返回{id:1,name:Swoole}。携带非法 Tokencurl-HAuthorization: Bearer wrong-tokenhttp://localhost:9501/api/user返回 401。进阶在ApiController中获取传递的user_idpublicfunctionuser(){$userId$this-request-getAttribute(user_id);return[id$userId,nameSwoole];}这展示了中间件向控制器传递数据的标准方式。实战 2跨域中间件全局中间件在前后端分离开发中跨域请求默认被浏览器拦截。我们可以编写一个全局中间件统一添加 CORS 头。创建app/Middleware/CorsMiddleware.php?phpnamespaceApp\Middleware;usePsr\Http\Message\ResponseInterface;usePsr\Http\Message\ServerRequestInterface;usePsr\Http\Server\MiddlewareInterface;usePsr\Http\Server\RequestHandlerInterface;classCorsMiddlewareimplementsMiddlewareInterface{publicfunctionprocess(ServerRequestInterface$request,RequestHandlerInterface$handler):ResponseInterface{// 对于 OPTIONS 预检请求直接返回 200 并附加头信息if($request-getMethod()OPTIONS){$response\Hyperf\Utils\ApplicationContext::getContainer()-get(\Hyperf\HttpServer\Contract\ResponseInterface::class)-withStatus(200);}else{$response$handler-handle($request);}// 统一添加 CORS 头return$response-withHeader(Access-Control-Allow-Origin,*)-withHeader(Access-Control-Allow-Headers,Content-Type, Authorization)-withHeader(Access-Control-Allow-Methods,GET, POST, PUT, DELETE, OPTIONS);}}注册为全局中间件打开config/autoload/middlewares.php如果没有这个文件则创建?phpreturn[http[\App\Middleware\CorsMiddleware::class,],];现在所有请求的响应都会带上 CORS 头。你可以用浏览器控制台测试跨域请求或者用 curl 查看响应头curl-vhttp://localhost:9501/api/user会看到Access-Control-Allow-Origin: *等头。实战 3参数加解密中间件注解中间件为增加趣味性我们实现一个简单的“前端加密请求体后端自动解密后端加密响应体前端解密”的中间件。我们定义两个注解DecryptRequest和EncryptResponse。第一步创建注解类新建app/Annotation/DecryptRequest.php?phpnamespaceApp\Annotation;useHyperf\Di\Annotation\AbstractAnnotation;#[Attribute(Attribute::TARGET_METHOD)]classDecryptRequestextendsAbstractAnnotation{}同理创建app/Annotation/EncryptResponse.php。第二步实现解密中间件创建app/Middleware/DecryptRequestMiddleware.php?phpnamespaceApp\Middleware;useApp\Annotation\DecryptRequest;useHyperf\Di\Annotation\AnnotationCollector;usePsr\Http\Message\ResponseInterface;usePsr\Http\Message\ServerRequestInterface;usePsr\Http\Server\MiddlewareInterface;usePsr\Http\Server\RequestHandlerInterface;useHyperf\HttpServer\Router\Dispatched;classDecryptRequestMiddlewareimplementsMiddlewareInterface{publicfunctionprocess(ServerRequestInterface$request,RequestHandlerInterface$handler):ResponseInterface{// 获取匹配到的路由信息$dispatched$request-getAttribute(Dispatched::class);if($dispatched$dispatched-handler?-callback){$callback$dispatched-handler-callback;// 如果控制器方法上标记了 DecryptRequest 注解if(is_array($callback)count($callback)2){[$class,$method]$callback;$annotationsAnnotationCollector::getClassMethodAnnotation($class,$method);if(isset($annotations[DecryptRequest::class])){// 读取加密的请求体假设前端用 base64 编码$body(string)$request-getBody();$decodedbase64_decode($body,true);if($decoded!false){// 构造新的请求体用解密后的数据替换$streamnew\Hyperf\HttpMessage\Stream\SwooleStream($decoded);$request$request-withBody($stream);// 重新解析 POST 参数如果需要$request$request-withParsedBody(json_decode($decoded,true)??[]);}}}}return$handler-handle($request);}}注意这里我们通过AnnotationCollector获取方法注解并在中间件中动态判断。因为注解中间件需要绑定到类或方法上我们可以直接在注解中携带中间件类名。更简单的方式是使用 Hyperf 的#[Middleware(DecryptRequestMiddleware::class)]注解不过为了展示注解中间件我们采用方案定义一个注解然后在全局中间件中监听该注解。这里为了清晰我们采用官方推荐的注解中间件方式直接在控制器方法上使用#[Middleware]注解引入中间件。简化版注解中间件Hyperf 允许你在控制器方法上直接指定中间件而不需要自定义注解useHyperf\HttpServer\Annotation\Middleware;useApp\Middleware\DecryptRequestMiddleware;useApp\Middleware\EncryptResponseMiddleware;#[Controller(prefix:/api)]classApiControllerextendsAbstractController{#[RequestMapping(path:secure,methods:post)]#[Middleware(DecryptRequestMiddleware::class)]#[Middleware(EncryptResponseMiddleware::class)]publicfunctionsecure(){$data$this-request-all();return[received$data,extrasecret];}}我们来实现这两个中间件DecryptRequestMiddleware简化直接用于注解?phpnamespaceApp\Middleware;useHyperf\HttpMessage\Stream\SwooleStream;usePsr\Http\Message\ServerRequestInterface;usePsr\Http\Server\MiddlewareInterface;usePsr\Http\Server\RequestHandlerInterface;usePsr\Http\Message\ResponseInterface;classDecryptRequestMiddlewareimplementsMiddlewareInterface{publicfunctionprocess(ServerRequestInterface$request,RequestHandlerInterface$handler):ResponseInterface{$body(string)$request-getBody();// 假设加密内容为 base64 编码的 JSON$decodedbase64_decode($body,true);if($decoded){$streamnewSwooleStream($decoded);$request$request-withBody($stream);$request$request-withParsedBody(json_decode($decoded,true)??[]);}return$handler-handle($request);}}EncryptResponseMiddleware?phpnamespaceApp\Middleware;usePsr\Http\Message\ResponseInterface;usePsr\Http\Message\ServerRequestInterface;usePsr\Http\Server\MiddlewareInterface;usePsr\Http\Server\RequestHandlerInterface;useHyperf\HttpMessage\Stream\SwooleStream;classEncryptResponseMiddlewareimplementsMiddlewareInterface{publicfunctionprocess(ServerRequestInterface$request,RequestHandlerInterface$handler):ResponseInterface{$response$handler-handle($request);$body(string)$response-getBody();// 将响应体 base64 加密$encryptedbase64_encode($body);return$response-withBody(newSwooleStream($encrypted))-withHeader(Content-Type,text/plain);// 改变类型}}测试加密中间件# 发送加密的请求体原始 JSON 的 base64curl-XPOST http://localhost:9501/api/secure-d$(echo-n{username:admin}|base64)返回的响应是加密后的 base64解码后可见原始 JSON。四、成果测试与执行顺序观察约 1 小时1. Token 中间件测试清单场景测试命令预期结果无 Tokencurl /api/user401 JSON 错误错误 Tokencurl -H Authorization: Bearer wrong /api/user401正确 Tokencurl -H Authorization: Bearer secret-api-token /api/user200返回用户数据携带 Token 但访问非保护路由curl -H Authorization: Bearer secret-api-token /health200正常不应该被拦截2. CORS 中间件测试curl-vhttp://localhost:9501/api/user# 查看响应头是否存在 Access-Control-Allow-Origin 等也可用浏览器打开一个前端页面用fetch请求跨域验证。3. 参数加解密中间件测试正常加密请求 解密响应# 加密请求PLAIN{action:test}ENC$(echo-n$PLAIN|base64)RESP$(curl-s-XPOST-d$ENChttp://localhost:9501/api/secure)echo响应密文:$RESPecho解密后响应:$(echo$RESP|base64-d)未加密请求直接发送 JSON看中间件是否报错应该不会被解密但可能会因为json_decode失败而返回空数组。4. 中间件执行顺序当一个方法上应用了多个中间件全局 CorsMiddleware - 路由 ApiTokenMiddleware - 注解 DecryptRequestMiddleware - 注解 EncryptResponseMiddleware执行顺序为前置全局 → 路由组 → 注解按声明顺序的前置部分后置注解 → 路由组 → 全局的后置部分你可以通过在各个中间件的process方法前后打印日志来验证。例如在CorsMiddleware中添加echo Cors Before\n; ... $response $handler-handle($request); echo Cors After\n;启动热重启发送请求查看终端输出顺序。五、今日作业与学习产出提交代码将ApiTokenMiddleware、CorsMiddleware、加解密中间件以及路由配置提交到 Git。学习笔记绘制中间件执行链的流程图标注全局、路由、注解中间件的注册位置和调用顺序。进阶任务为 Token 中间件增加路径排除功能比如/api/public不需要 Token可在中间件内判断$request-getUri()-getPath()。实现一个限流中间件基于 Redis 计数并在某个接口上注解使用体验中间件的复用性。思考题如果我们想在中间件中异步写日志使用协程但中间件的process方法必须返回 Response能否在handler-handle()之后go一个协程做日志写入这样是否会阻塞答案是可以因为协程不会阻塞但要注意上下文问题。尝试写一个日志中间件异步记录请求日志。通过今天的学习你已经掌握了 Hyperf 中间件的精髓能灵活运用它来构建安全的 API 网关层。明天我们将继续深化使用验证器和异常处理器让 API 更加健壮。

相关新闻

五、C++新特性、关键字与编译原理

五、C++新特性、关键字与编译原理

五、C新特性、关键字与编译原理&#xff08;共25项&#xff09;1.C/C中宏定义的相关知识2.C/C中typedef关键字的相关知识3.介绍一下register关键字4.介绍一下const关键字5.介绍一下external关键字6.介绍一下volatile关键字7.介绍一下dynamic在什么时候使用8.#include<file.h…

2026/8/26 15:56:29 阅读更多 →
把 TAPD / 飞书需求变成可审核的 AI 开发流程

把 TAPD / 飞书需求变成可审核的 AI 开发流程

我做了一个 Req2Code&#xff0c;让 Codex、Claude Code 和 Cursor 从多平台工作项选择一路走到规划分析、开发、测试与人工发布审批 “让 AI 开发不只会改代码&#xff0c;还能被选择、被追踪、被审核&#xff0c;并且只在明确批准后发布。” Req2Code 0.10.0 Alpha P…

2026/8/26 15:58:09 阅读更多 →
基于Spark的酷狗网络歌曲推荐系统设计与实现机器学习算法机器学习实战

基于Spark的酷狗网络歌曲推荐系统设计与实现机器学习算法机器学习实战

本系统基于Spark大数据处理框架&#xff0c;结合Django后端开发、Vue前端展示、MySQL数据库存储以及卷积神经网络&#xff08;CNN&#xff09;推荐算法&#xff0c;设计并实现了一款酷狗网络歌曲推荐系统。系统分为用户功能模块和管理员功能模块&#xff0c;用户模块包括首页、…

2026/8/26 15:55:35 阅读更多 →

最新新闻

电池出口美国必看!UL/FCC/UN38.3三大认证缺一不可,避坑指南

电池出口美国必看!UL/FCC/UN38.3三大认证缺一不可,避坑指南

您是否正在为电池产品开拓广阔的美国市场&#xff0c;却被繁杂的认证标准弄得一头雾水&#xff1f;是否担心因不合规而导致货物被扣、巨额罚款甚至被电商平台下架&#xff1f; 美国市场对电池产品的准入要求极为严格&#xff0c;提前做好合规认证是您成功出口的唯一捷径。作为专…

2026/8/26 17:59:32 阅读更多 →
跨境卖家必看:婴儿学步车美国市场准入标准全解

跨境卖家必看:婴儿学步车美国市场准入标准全解

一、核心标准体系 美国对婴儿学步车建立了 "强制性联邦法规 自愿性行业标准"双轨并行 的监管体系&#xff1a; 关键点 &#xff1a;亚马逊美国站要求婴儿学步车必须同时满足 16 CFR 1216 和 CPSIA 要求&#xff0c;两者缺一不可。 二、16 CFR 1216 — 联邦强制安全标…

2026/8/26 17:59:32 阅读更多 →
小鸿AI全攻略:从开箱配网到打造专属语音智能体

小鸿AI全攻略:从开箱配网到打造专属语音智能体

基于 OpenHarmony 星闪 RISC-V 的全开源端侧 AI 硬件&#xff0c;从配网到拥有专属语音助手 引言&#xff1a;当硬件遇到AI 在接触小鸿AI之前&#xff0c;我对“端侧AI”的理解还停留在各种开发板的跑分和算力参数上。直到我亲手将这台基于OpenHarmony、采用RISC-V架构并支持…

2026/8/26 17:59:32 阅读更多 →
59. 【Java】Spring Boot 入门:第一个 Web 应用

59. 【Java】Spring Boot 入门:第一个 Web 应用

摘要&#xff1a; 本文是Spring Boot入门实战指南&#xff0c;从零开始手把手教你创建第一个Spring Boot应用。文章详细介绍了Spring Boot的核心概念、自动配置机制、起步依赖原理&#xff0c;并通过Hello World和用户管理API两个完整示例&#xff0c;展示如何快速构建RESTful …

2026/8/26 17:59:32 阅读更多 →
Bianfchheng (Jiiu ) 《边城(九)》全文汉语拼音字母标调实测案例

Bianfchheng (Jiiu ) 《边城(九)》全文汉语拼音字母标调实测案例

此文基于这项规则&#xff1a;汉语拼音字母标调规则 Bianfchheng (Jiiu ) Shenv Conwen Zuqfuc hhuija shh, dayuem yv jiangjnn pngchhang ch zaofann shhjje l, janpshang shoushang quansh dongxi. Yi shang xio shantou biann haan Cuicui, yao Cuicui la chuand gos xi…

2026/8/26 17:59:32 阅读更多 →
VS Code C/C++ 插件 cpptools 内存占用异常

VS Code C/C++ 插件 cpptools 内存占用异常

前期概要 使用VS code连接WSL经常性出现终端和IDE卡住无法使用&#xff0c;关闭VS后即正常。 根本原因 cpptools 吃内存 "全量符号索引常驻" "多文件夹多实例" "可能的宏/symlink 泄漏" "没用 compile_commands 限制范围" 内存…

2026/8/26 17:58:32 阅读更多 →

日新闻

Python random 模块常用函数详解:从入门到实战

Python random 模块常用函数详解:从入门到实战

目录 1. 引言2. 准备工作3. 基础随机函数4. 序列相关函数5. 随机种子与复现6. 实战案例7. 注意事项8. 常见问题与排查9. 总结 1. 引言 摘要&#xff1a; 本文系统介绍 Python 标准库 random 模块中最常用的随机数生成函数。内容涵盖基础随机函数&#xff08;random()、unifor…

2026/8/26 0:00:40 阅读更多 →
《Microsoft Sql server 2008 Internals》读书笔记--第三章Databases and Database Files(2)

《Microsoft Sql server 2008 Internals》读书笔记--第三章Databases and Database Files(2)

《Microsoft Sql server 2008 Internals》索引目录&#xff1a; 《Microsoft Sql server 2008 Internals》读书笔记--目录索引 在上篇文章中&#xff0c;主要介绍了创建数据库的基本语法和FileGroup的初步知识。需要注意的是: 关于FileGroup 如果你的系统是用Raid设备直接存…

2026/8/26 1:18:18 阅读更多 →
政务AI智能体怎么建?三种模式、三步路径与四个误区

政务AI智能体怎么建?三种模式、三步路径与四个误区

政务AI智能体已经从概念试点阶段&#xff0c;转入了政务服务的常态化落地应用&#xff1b;在实际使用过程中&#xff0c;它能自主理解办事需求、辅助完成填报申报、开展材料预审&#xff0c;并联动多个系统协同作业&#xff0c;真正嵌入到政务办理的全流程当中。但在落地推进过…

2026/8/26 1:18:18 阅读更多 →

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态&#xff0c;宏观上观察到的光是由无数个微观的光量子组成的&#xff0c;每个光子在产生的瞬间&#xff0c;其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前&#xff0c;在微观层面&#xff0c;每个光量子的运动轨迹是以波函数所展现…

2026/8/26 14:45:33 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”&#xff0c;而是SIP会话的动态重定向你有没有遇到过这样的场景&#xff1a;客服坐席A正在和客户通电话&#xff0c;突然需要把这通对话无缝转给专家坐席B&#xff0c;客户完全感知不到中间的断连——既没听到忙音&#xff0c;也没被要求重新拨号…

2026/8/26 17:46:43 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack&#xff1f;如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法&#xff0c;那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/26 14:46:37 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速&#xff1a;macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/26 3:50:20 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南&#xff1a;3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗&#xff1f;ncmdump解密工具帮你轻松解决这个困…

2026/8/26 17:46:39 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片&#xff1a;为英语学习 App 打造桌面级学习助手适用平台&#xff1a;HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0&#xff08;API 26 Beta&#xff09;新增了 AgentCard 智能体卡片能力&#xff0c;这是继 HMAF&#xff08;鸿蒙智能体框架&#x…

2026/8/26 1:24:05 阅读更多 →