
本文介绍通过自定义中间件将动态查询结果(如 $data1)注入请求对象,实现多控制器间安全、高效、可维护的变量共享。适用于表单分步提交等需传递临时业务数据的场景。
本文介绍通过自定义中间件将动态查询结果(如 `$data1`)注入请求对象,实现多控制器间安全、高效、可维护的变量共享。适用于表单分步提交等需传递临时业务数据的场景。
在 Laravel 应用中,当业务流程涉及多步骤表单(例如:第一步选择预约时间/房间 → 第二步填写消息内容),常需将前一步的查询结果(如匹配的 user_id 列表)安全地传递至后续控制器。直接使用全局变量、Session 存储或重复查询均存在耦合高、易出错或性能差等问题。推荐方案是通过自定义中间件统一注入请求数据,既保持控制器无状态性,又确保数据时效性与作用域清晰。
✅ 正确做法:创建中间件注入动态数据
首先,生成中间件:
php artisan make:middleware CommonData
编辑 app/Http/Middleware/CommonData.php,在 handle() 方法中执行查询并合并到请求:
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use App\Models\Reservation; // 建议使用模型类而非 Facade
use Carbon\Carbon;
class CommonData
{
public function handle(Request $request, Closure $next)
{
// ✅ 仅在必要时执行查询:检查关键参数是否存在
if ($request->filled('date') && $request->filled('time') && $request->filled('room_id')) {
$data1 = Reservation::select('user_id')
->where('date', $request->date)
->where('time', $request->time)
->where('room_id', $request->room_id)
->get(); // 返回 Collection;若只需单值,可用 ->pluck('user_id')->first()
// 注入请求实例(推荐用 $request->merge() 或直接属性赋值)
$request->attributes->add(['data1' => $data1]);
}
return $next($request);
}
}
⚠️ 注意:
- 使用 Request $request 类型提示和 $request->xxx 语法替代 request('xxx'),更安全且支持 IDE 提示;
- 查询前校验参数存在性($request->filled()),避免空条件导致全表扫描;
- 推荐使用 Eloquent 模型(Reservation::)而非 reservation::(非标准命名,易引发命名空间错误)。
? 在控制器中使用共享数据
在 SecondController 中,无需额外声明,直接从请求中获取:
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
<?php namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Message;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class SecondController extends Controller
{
public function store(Request $request)
{
// ✅ 安全获取注入的数据(自动为 Collection 或 null)
$data1 = $request->attributes->get('data1', collect());
$msg = new Message();
$msg->date = Carbon::now();
$msg->content = $request->input('content');
$msg->user_id = Auth::user()->id;
$msg->receiver = $data1->pluck('user_id')->implode(','); // 示例:拼接 ID 字符串
// 或 $msg->receiver_user_ids = $data1->pluck('user_id')->toArray(); // 存数组
$msg->save();
return redirect()->back()->with('success', '消息已发送');
}
}
? 路由注册与作用域控制
在 routes/web.php 中,仅对需要共享数据的路由组应用该中间件,避免全局污染:
// 仅作用于预约相关流程的路由
Route::middleware(['common.data'])->group(function () {
Route::post('/step-one', [FirstController::class, 'store'])->name('reservation.step.one');
Route::post('/step-two', [SecondController::class, 'store'])->name('message.store');
});
并在 app/Http/Kernel.php 的 $routeMiddleware 中注册:
'common.data' => \App\Http\Middleware\CommonData::class,
❌ 不推荐的替代方案说明
- Session 存储:易因用户多步操作交叉导致数据错乱,且需手动清理;
- View Share / View Composer:仅限视图层,控制器不可用;
- Config 或 Service Container 绑定:数据无法按请求动态变化;
- 静态属性或全局变量:严重破坏请求隔离性,线程不安全。
✅ 总结
通过中间件注入请求属性的方式,实现了:
- 动态性:每次请求独立执行查询,数据实时准确;
- 解耦性:控制器无需关心数据来源,专注业务逻辑;
- 可维护性:数据组装逻辑集中一处,便于调试与扩展;
- 安全性:作用域严格限定于指定路由,无副作用。
此模式契合 Laravel 的请求生命周期理念,是跨控制器共享上下文数据的最佳实践之一。










