Laravel如何在服务提供者层全局为所有路由默认启用原子锁?
全局开启Laravel Session原子锁阻塞的实现方案
你不需要逐个路由调用block(),也不用纠结路由组不支持链式调用block()的问题,有两种开箱即用的方案可以全局生效,适配SPA并发请求的场景:
方案1:自定义Session启动中间件(最稳定,推荐)
路由上的block()方法本质是给StartSession中间件传参,控制是否启用原子锁、锁等待/持有超时时间,你可以直接重写该中间件的默认逻辑,全局对所有走web中间件的请求启用阻塞:
- 新建自定义中间件继承框架自带的StartSession:
<?php namespace App\Http\Middleware; use Illuminate\Session\Middleware\StartSession as FrameworkStartSession; class StartSession extends FrameworkStartSession { // 所有请求默认开启session阻塞 protected function shouldBlock($request) { // 可以在这里加判断排除不需要阻塞的路由,比如支付回调、静态资源接口、长耗时导出接口 return true; } // 请求等待锁的最长超时时间(秒),对应block()第一个参数 protected function blockWaitSeconds($request) { return 10; } // 单个请求持有锁的最长时间(秒),对应block()第二个参数 protected function blockLockSeconds($request) { return 10; } }
- 打开
app/Http/Kernel.php,在$middlewareGroups的web组中,把原来框架自带的StartSession替换成你刚才写的自定义中间件:
protected $middlewareGroups = [ 'web' => [ // 注释掉原来的框架自带Session中间件 // \Illuminate\Session\Middleware\StartSession::class, // 替换为自定义的 \App\Http\Middleware\StartSession::class, // 其他原有中间件保持不变... ], ];
方案2:服务提供者全局给路由注入block配置
如果你不想改中间件,可以直接在AppServiceProvider的boot方法中监听路由匹配事件,给所有web路由自动加上block配置:
// app/Providers/AppServiceProvider.php use Illuminate\Support\Facades\Route; public function boot() { Route::matched(function ($event) { $route = $event->route; // 仅给走web中间件、需要session的路由加配置,排除api等无状态路由 if (in_array('web', $route->gatherMiddleware())) { // 参数和block()方法一致:等待锁超时10秒,持有锁超时10秒 $route->block(10, 10); } }); }
配置注意事项
- 超时时间不要设置过长,否则并发请求会排队等待过久导致前端接口响应变慢,常规业务场景设置10秒足够覆盖绝大多数请求的处理时长
- 长耗时接口(比如大文件导出、批量数据处理)建议单独加路由配置,调整更长的锁时间,或者直接排除在全局阻塞逻辑外,避免锁长期占用阻塞其他正常请求
- 你当前使用database作为session驱动且已经部署官方标准Schema,不需要额外调整数据库结构,配置完直接生效,能彻底解决并发写session导致的token冲突、419异常退出问题
Route::group()->block()不生效的原因是block方法仅属于单个路由实例,路由组本身没有实现批量向下传递block配置的逻辑,所以链式调用组的block方法不会对组内路由产生效果。
内容的提问来源于stack exchange,提问作者Jaquarh
相关产品推荐
相关产品推荐

