You need to enable JavaScript to run this app. 为什么我的异步jQuery Ajax调用会阻塞其他轮询请求?
优惠活动
大模型
产品
解决方案
定价
更多

为什么我的异步jQuery Ajax调用会阻塞其他轮询请求?

问题根因

你的问题核心是PHP会话独占锁导致的:PHP默认使用文件存储会话时,会对同一个客户端的会话文件加独占锁,同一时间只能处理一个来自同一会话的请求。你触发导入请求后,该请求会一直持有会话锁直到处理完成,后续所有同会话的loadprogress请求都会被阻塞排队,直到导入结束锁释放才会依次执行,所以会出现进度请求全部卡到导入完成后才返回的现象。


解决方案

1. 导入接口提前释放会话锁(成本最低的快速修复方案)

你只需要在导入接口的业务逻辑执行前,完成权限校验、参数验证等需要用到会话的操作后,立即释放会话锁即可,示例代码如下:

use Illuminate\Support\Facades\Cache;

public function import(Request $request)
{
    // 先完成所有需要用到会话的操作:权限校验、参数校验等
    abort_if(!auth()->check(), 403);
    $validated = $request->validate([
        // 你的参数校验规则
    ]);
    
    // 校验完成后立即释放会话锁,不影响后续进度请求
    session()->save();
    // 也可以用原生PHP函数:session_write_close();
    
    // 后续执行导入业务逻辑
    $totalRecords = count($excelRecords);
    foreach ($excelRecords as $index => $record) {
        // 处理单条交易记录
        $this->processSingleRecord($record);
        // 进度写入缓存,关联当前用户ID避免不同用户进度冲突
        Cache::put('import_progress_'.auth()->id(), ceil(($index + 1) / $totalRecords * 100), 600);
    }
    // 导入完成后清理进度缓存
    Cache::forget('import_progress_'.auth()->id());
    
    return response()->json(['status' => 'success']);
}

对应的进度查询接口示例:

public function loadProgress()
{
    abort_if(!auth()->check(), 403);
    return response()->json([
        'progress' => Cache::get('import_progress_'.auth()->id(), 0)
    ]);
}

2. 改用队列异步处理导入任务(更推荐的生产级方案)

目前你的导入逻辑直接跑在Web请求中,总耗时约80秒,很容易触发PHP、Web服务器的超时限制导致导入中断,更合理的方案是把导入逻辑丢到异步队列执行:

  • 前端触发导入请求后,后端生成唯一任务ID,立即将导入任务推送到队列,返回任务ID给前端
  • 导入任务执行过程中,将进度写入缓存(如Redis),关联对应任务ID
  • 前端轮询时携带任务ID调用loadprogress接口,从缓存中读取对应进度返回
    这种方案完全规避了会话锁问题,也避免了Web请求超时的风险,适合长期使用。

前端优化建议

当前轮询间隔设置为100ms过于频繁,对服务器压力较大,调整为1000ms即可满足进度展示的实时性需求,只需要修改JS代码中的setTimeout(loadProgress, 1000)即可。

内容的提问来源于stack exchange,提问作者Peter F.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 06:27:03