laravel 的 pipeline 不是为请求处理链设计的,而是通用串行函数调用工具,适用于明确控制输入输出且不依赖 http 生命周期的场景,如订单状态变更、api 响应组装、cli 数据清洗。

直接说结论:Laravel 的 Pipeline 不是为“请求处理链”设计的,硬套进 HTTP 生命周期容易出错、难调试、绕过中间件机制。
什么时候该用 Pipeline?
它本质是个通用的「串行函数调用工具」,适合你明确控制输入/输出、且不依赖 Laravel 请求生命周期的场景。比如:
- 批量处理订单状态变更(
OrderStatusPipeline) - 构建自定义 API 响应组装逻辑(如先查缓存、再查 DB、最后格式化)
- 在命令行任务里做多步数据清洗(
ImportDataPipeline)
别把它当 middleware 的平替——Laravel 的中间件走的是 Illuminate\Pipeline\Pipeline 底层,但封装了路由匹配、异常捕获、响应返回等完整流程;而你手动 new 一个 Pipeline,这些全得自己兜底。
Pipeline 的典型误用:在控制器里强行链式处理请求
常见错误写法:
return app(Pipeline::class)
->send($request)
->through([
EnsureUserCanEditPost::class,
ValidatePostUpdate::class,
SanitizePostContent::class
])
->then(function ($request) {
return Post::update(...);
});
问题很实在:
-
EnsureUserCanEditPost这类中间件通常 expect 接收$request和$next,但Pipeline::then()传进去的只是$request,$next根本没出现 → 直接报Undefined variable: next - 中间件里写的
return response()->json(...)在 pipeline 里不会中断执行,后续步骤照常跑,结果可能覆盖前面的响应 - 所有中间件的
handle()方法必须改成单参数(只收$passable),和全局中间件定义不兼容,维护成本飙升
真要链式处理请求,用中间件组 + 路由分组
这才是 Laravel 原生支持、可复用、可调试的方案:
- 把逻辑拆成标准中间件,每个都实现
handle($request, Closure $next) - 在
app/Http/Kernel.php里注册为$middlewareGroups['api']或自定义组 - 路由直接绑定:
Route::put('/posts/{id}', [PostController::class, 'update'])->middleware(['can:edit,post', 'validate:update_post']);
优势很明显:异常自动转 HTTP 响应、日志自动记录、能用 dd() 断点调试每一步、支持 except/only 精确控制。
如果非要用 Pipeline,注意三个硬约束
它不是黑盒,几个关键点卡住就崩:
- 所有闭包或类的
handle()方法必须返回值(哪怕只是return $passable;),否则下一级收不到输入 - 不能在任意环节 throw 异常后指望 Laravel 自动渲染 —— 你得自己 try/catch 并调
response() -
through()里的类必须可被容器解析(有对应 binding 或默认构造器),否则报Target class does not exist
示例安全写法:
$result = app(Pipeline::class)
->send($data)
->through([
fn($carry, $next) => $carry['status'] === 'draft' ? $next($carry) : throw new \Exception('Not draft'),
fn($carry, $next) => array_merge($carry, ['processed_at' => now()]),
])
->then(fn($carry) => Post::create($carry));
真正难的不是写通 pipeline,而是判断「这个逻辑到底该不该放 pipeline 里」——多数时候,答案是否定的。它太裸,太靠近底层,而 Laravel 已经为你铺好了更稳的路。










