Laravel 6将Mailable转为队列时遇Closure序列化不允许错误
解决Mailable队列化的两个异常问题
问题根源分析
你遇到的两个问题本质都是序列化问题和依赖注入错误:
- 传
Request对象到Mailable导致序列化失败:Request实例内部包含Closure(比如验证规则、回调逻辑),PHP无法序列化Closure,所以触发"Serialization of 'Closure' is not allowed"。 - 禁用构造函数直接在
build注入变量:Laravel的Mailable默认不会自动给build方法注入请求对象,容器找不到对应绑定,所以抛出BindingResolutionException。
修复方案
核心思路是不要传递Request对象,直接传递已创建的模型实例,利用Laravel的SerializesModels特性处理序列化逻辑。
1. 修改控制器代码
直接把创建好的Contact模型实例传给Mailable,不需要给request手动加id:
public function store(ContactsStoreRequest $request) { $validated = $request->validated(); $submission = Contact::create($validated); // 用验证后的数据更安全 $emails = explode(',', config('mail.mailto')); $when = now()->addMinutes(1); Mail::to($emails) ->bcc(['notifications@xxxx.com']) ->later($when, new ContactSubmission($submission)); // 传模型实例而非request return redirect('/contact/#loc')->with('status', 'success'); }
2. 修改邮件类代码
让构造函数接收Contact模型,利用SerializesModels自动处理序列化:
namespace App\Mail; use App\Models\Contact; // 引入你的Contact模型 use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Mail\Mailable; use Illuminate\Queue\SerializesModels; class ContactSubmission extends Mailable implements ShouldQueue { use Queueable, SerializesModels; public Contact $submission; // 定义模型类型,更清晰 /** * Create a new message instance. * * @return void */ public function __construct(Contact $submission) { $this->submission = $submission; } /** * Build the message. * * @return $this */ public function build() { return $this->view('emails.contact-submission') ->subject('XXX - Contact Submission #' . $this->submission->id) ->replyTo($this->submission->email_address); } }
关键说明
SerializesModels特性会自动把模型序列化为主键ID,队列执行时Laravel会重新从数据库查询完整模型,既避免了序列化大对象,也彻底解决了Closure无法序列化的问题。- 修改代码后,记得重启队列worker:
php artisan queue:restart,否则worker会使用旧的代码缓存。
内容的提问来源于stack exchange,提问作者LuRKeR
相关产品推荐
相关产品推荐

