Laravel 12 为所有队列任务应用全局中间件(类Web的withMiddleware)
Laravel 12 全局队列中间件实现方案(多租户场景)
核心思路
利用Laravel的总线(Bus)系统全局管道,为所有队列化任务(自定义任务、通知、队列事件、队列邮件等)自动注入多租户配置中间件,无需逐个修改任务类。
具体实现步骤
1. 注册全局总线管道中间件
在App\Providers\AppServiceProvider的boot方法中,添加全局中间件注册逻辑:
use Illuminate\Support\Facades\Bus; use App\Http\Middleware\ConfigureJobTenantMiddleware; // 替换为你的中间件实际路径 public function boot() { // 为所有总线任务(含队列任务)绑定全局中间件 Bus::pipeThrough([ ConfigureJobTenantMiddleware::class, ]); }
2. 适配中间件处理逻辑
调整你的ConfigureJobTenantMiddleware,兼容不同类型队列任务的tenant_id提取与配置切换:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Contracts\Queue\ShouldQueue; class ConfigureJobTenantMiddleware { public function handle($job, Closure $next) { if ($job instanceof ShouldQueue) { $tenantId = $this->extractTenantId($job); if ($tenantId) { // 保存原始配置,执行后恢复(避免污染后续任务) $originalMailConfig = config('mail.default'); // 设置租户专属配置,示例:切换邮件驱动、应用URL等 config(['mail.default' => "tenant_{$tenantId}_mail"]); config(['app.url' => "https://tenant{$tenantId}.yourdomain.com"]); } } // 执行任务 $result = $next($job); // 恢复原始配置 if (isset($originalMailConfig)) { config(['mail.default' => $originalMailConfig]); } return $result; } /** * 从不同类型队列任务中提取tenant_id */ private function extractTenantId($job) { // 处理自定义任务:任务自身携带tenantId属性 if (property_exists($job, 'tenantId')) { return $job->tenantId; } // 处理队列通知:从通知的Notifiable实例中获取 if (method_exists($job, 'getNotifiable')) { $notifiable = $job->getNotifiable(); return $notifiable->tenant_id ?? null; } // 处理队列邮件:从邮件实例关联的用户模型中获取 if (method_exists($job, 'mailable') && $job->mailable) { $mailable = $job->mailable; return $mailable->user?->tenant_id ?? null; } // 处理队列事件:从事件实例中获取 if (method_exists($job, 'event') && $job->event) { $event = $job->event; return $event->tenantId ?? $event->model?->tenant_id ?? null; } return null; } }
3. 验证生效范围
该方案会自动覆盖所有Laravel总线分发的队列任务:
- 自定义队列任务(实现
ShouldQueue接口) - 队列化通知(
Notification::queue()/sendLater()) - 队列化邮件(
Mail::queue()/sendLater()) - 队列化事件(
Event::dispatchAfterResponse()/queue())
关键注意事项
- 配置隔离:队列任务异步执行,必须在任务结束后恢复原始配置,防止影响后续任务的运行环境。
- 序列化兼容性:任务中传递的模型建议只携带ID,在中间件中重新查询完整模型,避免序列化/反序列化丢失数据。
- 异常防护:添加
try-catch逻辑处理tenant_id缺失的情况,避免任务因配置失败而中断。
内容的提问来源于stack exchange,提问作者Joe Nyambura
相关产品推荐
相关产品推荐

