我如何在Laravel应用原子锁到我所有的路由?



我有一个单页应用程序,它通过axios计算多个AJAX请求。偶尔,我遇到这样一种情况,两个请求同时异步运行,并试图写入会话,导致419响应代码,其中CSRF令牌在响应中被删除,迫使我不得不注销用户。

调试后,我遇到了使用原子锁的会话阻塞。

我的会话提供者是数据库,我有Laravel附带的标准Schema来实现这个功能。目前,我必须在我的路由上这样指定:

Route::any('/example', [SomeController::class, 'someFunction')->block();

然而,我有大量的路由,并且由于应用程序是SPA,是否有一种方法可以在服务提供商级别默认实现这一点?

这是不可能的Route::group(...)->block()这是我所做的最初尝试。

实现这一点有点痛苦。但在我提出解决方案之前,先做一个简短的分析:

Route::block($lockSeconds = 10, $waitSeconds = 10)方法内部设置路由上的lockSecondswaitSeconds属性。如果这两个属性被添加到组定义中,它们实际上被传递给路由,但不幸的是在子密钥action:

Route::group(['lockSeconds' => 10, 'waitSeconds' => 10, 'prefix' => 'api/spa'], function () {
Route::get('foo', fn () => response()->json(['result' => 'ok']));
});
// Dump of the route
"api/spa/foo" => IlluminateRoutingRoute {#217 ▼
+uri: "api/spa/foo"
+methods: array:2 [▶]
+action: array:5 [▼
"middleware" => array:1 [▶]
"uses" => Closure() {#216 ▶}
"namespace" => null
"prefix" => ""
"where" => [],
"lockSeconds" => 10,             <-- we got the setting here
"waitSeconds" => 10              <--
]
+isFallback: false
+controller: null
+defaults: []
+wheres: []
+parameters: null
+parameterNames: null
#originalParameters: null
#withTrashedBindings: false
#lockSeconds: null                 <-- we want the setting here though
#waitSeconds: null                 <--
+computedMiddleware: null
+compiled: null
#router: IlluminateRoutingRouter {#25 ▶}
#container: IlluminateFoundationApplication {#3 ▶}
#bindingFields: []
}

这给我们留下的情况是,在路由注册期间定义这两个属性是不可能的。但幸运的是,我们还可以在将路由添加到路由集合后对它们进行操作:

foreach (Route::getRoutes() as $route) {
$route->block();
}

这段代码最好放在routes/web.php的底部或RouteServiceProvidermap()方法的末尾。当你这样做的时候,你可能还想过滤路由,只更新以给定前缀开头的路由:

foreach (Route::getRoutes() as $route) {
if (str_starts_with($route->uri(), 'api/spa')) {
$route->block();
}
}

最新更新