Relay不能直接composer create-project安装,因为它只是PSR-15调度器,无官方可创建项目包;正确做法是先composer init,再依次composer require relay/relay、nyholm/psr7等依赖。

Relay 为什么不能直接 composer create-project 安装
Relay 不是框架,也不是带骨架的项目模板,它只是一个纯 PSR-15 调度器,没有内置 installer 或 relay/relay-skeleton 这类包。运行 composer create-project relay/relay 会报 Could not find package relay/relay 或返回空仓库——因为官方从未发布过该命令支持的“可创建项目”包。
正确做法是:先用 composer init 初始化一个空项目(确保 PHP ≥ 8.0),再显式引入 Relay 及其依赖链:
-
composer require relay/relay—— 核心调度器,本身不带 HTTP 消息实现 -
composer require nyholm/psr7—— 推荐的轻量 PSR-7 实现(比 Diactoros 更快,无反射开销) -
composer require psr/http-server-middleware psr/http-server-handler—— 显式声明接口契约,避免 IDE 类型提示失效
Relay 的 RelayRelay 构造函数参数怎么填才不崩
Relay 实例化时只接受一个参数:array $middleware,即中间件数组。它**不接受 Router、RequestHandler 或 PSR-7 工厂对象**——这些是你自己组织请求流程时要处理的,Relay 只负责按序调用 process() 并传递 $handler。
常见错误写法:new RelayRelay([$router, $finalHandler]),结果报 Call to undefined method handle()。原因:Router 通常不是 MiddlewareInterface 实现,而 $finalHandler 若没包装成 RequestHandlerInterface,Relay 就无法传给下一个中间件。
正确组装方式:
- 所有中间件必须实现
MiddlewareInterface,且process()内必须调用$handler->handle($request) - 最终处理器(如响应生成逻辑)需包装为
RequestHandlerInterface实例,例如用new class implements RequestHandlerInterface { ... }或封装成闭包(但需手动适配) - 路由中间件(如
mezzio/mezzio-router)必须是 PSR-15 兼容的,不能直接塞 FastRoute 实例
Relay 和 Mezzio/Slim 的中间件注册方式差异在哪
Relay 是“裸调度器”,不提供 pipe()、add() 或配置文件加载机制。它只认一个数组,顺序即执行顺序,洋葱模型完全靠你手写数组顺序控制。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
对比之下:
- Mezzio 的
config/pipeline.php是 DSL 封装,底层仍转成 Relay-style 数组;但若你手动改数组却忘了更新 autoload 或命名空间映射,Class not found直接炸 - Slim v4+ 默认用
slim/slim自研调度器,虽兼容 PSR-15,但中间件注册走$app->add(),和 Relay 的构造传参模式不互通 - Relay 不自动解析
psr-4命名空间,也不扫描目录——类必须已加载,否则process()调用时才报错,排查成本高
所以,用 Relay 时,composer.json 的 autoload.psr-4 必须精确覆盖所有中间件路径,比如:"App\Middleware\": "src/Middleware/",漏掉斜杠或大小写不一致,运行时就找不到类。
为什么加了 middlewares/base-path 后 Relay 路由全 404
因为 middlewares/base-path 会修改 $request 的 URI(移除前缀),但它**不修改路由注册时用的原始路径模式**。如果你用 Relay 配合 mezzio/mezzio-router,而路由定义是 /api/users,但请求来的是 /my-app/api/users,base-path 把它变成 /api/users 后,路由匹配才能成功——前提是路由中间件在 base-path 之后执行。
关键点:中间件顺序决定一切。Relay 数组里,base-path 必须排在路由中间件之前:
new RelayRelay([
new MiddlewaresBasePath('/my-app'), // ✅ 先剥前缀
$router, // ✅ 再匹配 /api/users
$finalHandler
]);
反着写就永远 404;另外,base-path 依赖 PSR-7 的 withUri(),如果用的 PSR-7 实现(如旧版 Diactoros)不严格遵循不可变模式,URI 修改可能不生效——建议锁定 nyholm/psr7:^1.5。
Relay 的极简设计意味着它不帮你做任何假设,包括自动加载、路由绑定、错误兜底。真正容易被忽略的,是那个看似无关紧要的 autoload.psr-4 映射和中间件数组里的执行顺序——错一个字符,整个请求链就静默断裂,连日志都不打。


















