Laravel 9并发AJAX请求下会话数据丢失问题求助
会话竞态条件导致Laravel 9中部分会话变量丢失问题
问题场景
使用Laravel 9框架,会话存储采用Redis(此前为文件存储)。存在如下场景:
- 控制器方法
getReport将多组数据存入会话后返回视图 - 视图通过3个DataTables实例同时发起AJAX请求,调用同一控制器的
getAjaxData方法加载对应会话中的数据
当视图仅包含1个DataTables,或设置$.ajaxSetup({async: false})时功能正常;但同时发起2-3个请求时,前1-2个请求能成功返回数据,其余请求返回空白,对应会话变量丢失,现象不稳定,推测是竞态条件导致。
补充细节
- AJAX对应的
getAjaxData方法仅查询并返回JSON数据,不修改会话 - 问题发生时用户未登出,仅丢失部分自定义会话变量;频繁刷新AJAX URL(如
http://site.com/reports/ajax?key=12345)可稳定复现,缓慢刷新则不会出现 - 会话未完全销毁:用户仍保持登录状态,失败的AJAX请求仍能通过
customer守卫验证进入控制器,说明会话保留了token和守卫相关数据
数据存入会话的原因
这些数据生命周期较短(短于会话有效期),且各报表间存在交叉引用,需要统一查询处理;若让AJAX请求按需查询数据,会重复调用外部API并产生大量服务端额外处理开销。
已尝试的解决方案(均无效)
- 从文件存储切换为Redis存储会话,无改善
- 尝试为路由添加阻塞逻辑,无变化
- 试用
rairlie/laravel-locking-session扩展,但运行异常,且该库未针对Redis会话做测试 - 禁用AJAX路由的CSRF验证,无效
- 在
getAjaxData方法中添加调试代码,发现请求失败时会话仅包含token和守卫数据,自定义的report*_data变量完全丢失
示例代码
ReportController.php
class ReportController extends Controller { function getReport(Request $request) { session()->put('report1_data', $jsonData1); session()->put('report2_data', $jsonData2); session()->put('report3_data', $jsonData3); return view('reports'); } function getAjaxData(Request $request) { $result = json_decode(session()->get($request->get('key')), JSON_OBJECT_AS_ARRAY); return response()->json($result); } }
reports.blade.php
$(document).ready(function(){ $('#table_report1').DataTable({ ajax: '{{ URL::route('reports.ajaxdata',['key'=>'report1_data']) }}' }); $('#table_report2').DataTable({ ajax: '{{ URL::route('reports.ajaxdata',['key'=>'report2_data']) }}' }); $('#table_report3').DataTable({ ajax: '{{ URL::route('reports.ajaxdata',['key'=>'report3_data']) }}' }); });
web.php
Route::group(['middleware'=>['auth:customer']],function() { Route::controller(\App\Http\Controllers\ReportController::class)->group(function(){ Route::get('reports','getReport')->name('reports'); Route::get('ajax','getAjaxData')->name('reports.ajaxdata'); }); });
内容的提问来源于stack exchange,提问作者localhost
相关产品推荐
相关产品推荐

