roadrunner HTTP中间件开发:自定义请求处理管道实战
【免费下载链接】roadrunner 项目地址: https://gitcode.***/gh_mirrors/roa/roadrunner
在Web开发中,你是否经常需要对请求进行统一处理,如身份验证、日志记录、跨域控制等重复工作?传统PHP应用中,这些逻辑往往分散在各个控制器中,导致代码冗余且难以维护。本文将通过实战案例,演示如何使用roadrunner构建高效的HTTP中间件管道,实现请求处理逻辑的模块化与复用。
中间件基础:从请求到响应的处理链
roadrunner作为高性能PHP应用服务器,其HTTP中间件系统允许你在请求到达业务逻辑前或响应发送给客户端前插入自定义处理逻辑。中间件本质是一个"洋葱模型":每个中间件可以决定是否将请求传递给下一个中间件,或直接返回响应。
roadrunner的HTTP中间件生态已包含多种内置功能:
- gzip压缩:自动压缩响应内容
- 请求头管理:统一添加/修改HTTP头
- 静态文件服务:直接处理静态资源请求
- Prometheus监控:收集请求 metrics
开发准备:环境与工具链配置
开始开发前,确保环境满足以下要求:
- 安装roadrunner:
***poser require spiral/roadrunner-cli
./vendor/bin/rr get-binary
- 项目配置文件.rr.yaml基础结构:
version: '3'
http:
address: "0.0.0.0:8080"
middleware: ["logger", "cors"] # 中间件执行顺序
pool:
num_workers: 4
- 基础PHP工作器代码worker.php:
<?php
use Spiral\RoadRunner;
use Nyholm\Psr7;
include "vendor/autoload.php";
$worker = RoadRunner\Worker::create();
$psrFactory = new Psr7\Factory\Psr17Factory();
$worker = new RoadRunner\Http\PSR7Worker($worker, $psrFactory, $psrFactory, $psrFactory);
while ($req = $worker->waitRequest()) {
try {
$rsp = new Psr7\Response();
$rsp->getBody()->write('Hello world!');
$worker->respond($rsp);
} catch (\Throwable $e) {
$worker->getWorker()->error((string)$e);
}
}
实战一:请求日志中间件开发
功能需求
实现记录所有请求的方法、路径、耗时和响应状态码到日志文件。
实现步骤
- 创建中间件处理类
src/Middleware/LoggerMiddleware.php:
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Log\LoggerInterface;
class LoggerMiddleware implements MiddlewareInterface
{
private $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$startTime = microtime(true);
$method = $request->getMethod();
$uri = $request->getUri()->getPath();
// 继续处理请求
$response = $handler->handle($request);
// 计算请求耗时
$duration = round((microtime(true) - $startTime) * 1000, 2);
$status = $response->getStatusCode();
// 记录日志
$this->logger->info("{$method} {$uri} {$status} {$duration}ms");
return $response;
}
}
- 在工作器中注册中间件:
<?php
// worker.php (部分代码)
$worker = new RoadRunner\Http\PSR7Worker($worker, $psrFactory, $psrFactory, $psrFactory);
// 创建日志中间件
$logger = new \Monolog\Logger('http');
$logger->pushHandler(new \Monolog\Handler\StreamHandler('php://stdout'));
$loggerMiddleware = new App\Middleware\LoggerMiddleware($logger);
// 注册中间件栈
$dispatcher = new \Middlewares\Utils\Dispatcher([
$loggerMiddleware,
// 其他中间件...
function ($request, $handler) {
// 业务逻辑处理
$response = new Psr7\Response();
$response->getBody()->write('Hello from middleware!');
return $response;
}
]);
while ($req = $worker->waitRequest()) {
try {
$response = $dispatcher->dispatch($req);
$worker->respond($response);
} catch (\Throwable $e) {
$worker->getWorker()->error((string)$e);
}
}
- 配置文件启用中间件:
# .rr.yaml
http:
address: "0.0.0.0:8080"
middleware: ["logger"] # 对应中间件名称
实战二:API请求限流中间件
功能需求
实现基于IP地址的请求限流,防止API被过度调用。
实现步骤
- 创建限流中间件
src/Middleware/RateLimitMiddleware.php:
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Spiral\RoadRunner\KV\Factory;
use Spiral\RoadRunner\KV\KVInterface;
class RateLimitMiddleware implements MiddlewareInterface
{
private $kv;
private $limit = 100; // 每小时限制100次请求
private $window = 3600; // 时间窗口(秒)
public function __construct()
{
// 获取roadrunner KV存储实例
$this->kv = Factory::createFromConfig([
"driver" => "memory",
"config" => [
"interval" => 60
]
]);
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$ip = $request->getServerParams()['REMOTE_ADDR'] ?? 'unknown';
$key = "ratelimit:{$ip}";
// 获取当前请求计数
$count = (int)($this->kv->get($key) ?? 0);
if ($count >= $this->limit) {
// 超出限制,返回429 Too Many Requests
return (new \Nyholm\Psr7\Response())
->withStatus(429)
->withHeader('X-RateLimit-Limit', (string)$this->limit)
->withHeader('X-RateLimit-Remaining', '0');
}
// 增加计数
$this->kv->set($key, (string)($count + 1), $this->window);
// 继续处理请求
$response = $handler->handle($request);
// 添加限流响应头
return $response
->withHeader('X-RateLimit-Limit', (string)$this->limit)
->withHeader('X-RateLimit-Remaining', (string)($this->limit - $count - 1));
}
}
- 在调度器中添加限流中间件:
<?php
// worker.php (部分代码)
$dispatcher = new \Middlewares\Utils\Dispatcher([
$loggerMiddleware,
new App\Middleware\RateLimitMiddleware(), // 添加限流中间件
// 业务逻辑...
]);
限流中间件测试
使用curl测试限流效果:
# 连续发送请求
for i in {1..10}; do curl -I http://localhost:8080; done
正常响应头应包含:
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
当超出限制时:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
中间件调试与性能优化
调试技巧
- 使用app-logger插件记录中间件执行流程:
<?php
// 在中间件中添加详细日志
$this->logger->debug("Middleware executing", [
'middleware' => __CLASS__,
'request_id' => $request->getAttribute('request_id')
]);
- 启用roadrunner详细日志:
# .rr.yaml
logs:
level: debug # 默认为error
性能优化建议
- 减少中间件数量:只保留必要的中间件,避免过度嵌套
- 缓存计算结果:对频繁使用的计算结果进行缓存,如限流中间件中的IP解析
- 异步处理:非关键逻辑使用异步处理,如日志记录可使用jobs插件后台处理
<?php
// 异步记录日志示例
$jobs = RoadRunner\Jobs\Jobs::create($worker);
$jobs->dispatch(
'log_job',
json_encode(['message' => $logMessage]),
['queue' => 'logs']
);
部署与最佳实践
生产环境配置
- 使用环境变量区分配置:
# .rr.yaml
http:
address: ${HTTP_ADDRESS:0.0.0.0:8080}
middleware: ${HTTP_MIDDLEWARE:logger,cors}
- 调整工作进程数:
# .rr.yaml
server:
***mand: "php worker.php"
relay: pipes
pool:
num_workers: ${NUM_WORKERS:4} # 根据CPU核心数调整
中间件顺序最佳实践
中间件注册顺序遵循"先进后出"原则,推荐顺序:
- 日志/监控:最先执行,确保所有请求被记录
- 安全相关:如CORS、CSRF保护
- 认证/授权:验证用户身份
- 业务逻辑:请求处理核心逻辑
- 响应处理:如压缩、格式化
总结与后续学习
通过本文你已掌握:
- roadrunner中间件基本概念与工作原理
- 开发自定义中间件的完整流程
- 两个实用中间件(日志记录、请求限流)的实现
- 中间件调试与性能优化技巧
进阶学习资源
- 官方文档:了解更多内置中间件功能
- 中间件生态:探索roadrunner丰富插件系统
- 性能测试:使用基准测试评估中间件性能影响
实践挑战
尝试实现以下中间件来巩固所学:
- JWT认证中间件:验证API请求中的JWT令牌
- 请求验证中间件:使用JSON Schema验证请求数据
- 响应缓存中间件:缓存频繁访问的API响应
现在,你已具备构建高效、模块化请求处理管道的能力。合理设计的中间件系统将极大提升代码复用性和系统可维护性,为你的应用提供企业级架构支持。
提示:定期查看[CHANGELOG.md]了解roadrunner最新特性和中间件API变化。
【免费下载链接】roadrunner 项目地址: https://gitcode.***/gh_mirrors/roa/roadrunner