You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

向服务器传输并存储数据时如何避免丢失?短间隔传输丢数据解决方案

数据丢失原因
  • 前端层面:代码全局复用同一个XMLHttpRequest实例,高频调用sendData时,后一次请求执行XHR.open()会直接中断还未完成的前一次请求,直接导致前一次数据传输失败;同时原代码没有处理传输异常、特殊字符转义逻辑,也会导致数据传输失败。
  • 后端层面:存在读写竞态问题,多个请求同时读取data.json后,先后写入会覆盖前一次的写入结果,导致数据丢失;同时原代码没有处理文件初始化、JSON解析失败的异常场景,也会导致数据写入失败。
修复方案

前端优化代码

每次请求新建独立的XHR实例,新增请求队列、失败重试、特殊字符转义逻辑,避免请求被中断、传输失败丢数据:

// 本地待发送数据队列,失败请求自动重试
const pendingData = [];
let isSending = false;

function sendData(data) {
  // 数据先存入本地队列,避免传输过程丢失
  pendingData.push(data);
  processQueue();
}

function processQueue() {
  if (isSending || pendingData.length === 0) return;
  isSending = true;
  const currentData = pendingData[0];
  // 每次新建独立XHR实例,不复用全局实例
  const XHR = new XMLHttpRequest();
  XHR.open('POST', 'savedata.php');
  XHR.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
  XHR.onload = function() {
    if (XHR.status === 200) {
      // 发送成功移除队列头
      pendingData.shift();
    }
    isSending = false;
    // 处理下一条待发数据
    processQueue();
  };
  // 网络错误也触发队列继续处理,下次重试当前数据
  XHR.onerror = function() {
    isSending = false;
    processQueue();
  };
  // 新增encodeURIComponent处理特殊字符,避免解析错误
  XHR.send('data=' + encodeURIComponent(JSON.stringify(currentData)));
}

后端优化代码

新增文件独占锁、异常校验、文件初始化逻辑,解决竞态写入问题:

if (isset($_POST['data'])) {
    $inputData = json_decode($_POST['data']);
    // 校验传入数据合法性
    if (json_last_error() !== JSON_ERROR_NONE) {
        exit;
    }
    $filePath = 'data.json';
    // 文件不存在时初始化空数组
    if (!file_exists($filePath)) {
        file_put_contents($filePath, '[]', LOCK_EX);
    }
    // 打开文件并获取独占锁,阻塞直到拿到锁再执行读写
    $file = fopen($filePath, 'r+');
    if (flock($file, LOCK_EX)) {
        // 读取最新的文件内容
        $fileContent = fread($file, filesize($filePath));
        $accumulatedData = json_decode($fileContent);
        if (json_last_error() === JSON_ERROR_NONE && is_array($accumulatedData)) {
            array_push($accumulatedData, $inputData);
            $newContent = json_encode($accumulatedData);
            // 清空原有内容写入新数据
            ftruncate($file, 0);
            rewind($file);
            fwrite($file, $newContent);
        }
        // 写入完成释放锁
        flock($file, LOCK_UN);
    }
    fclose($file);
}

低并发场景下也可以直接用file_put_contents($filePath, $newContent, LOCK_EX)简化写入逻辑,底层会自动处理加锁逻辑。

高并发场景进阶优化

如果请求并发超过每秒几十次,文件存储本身IO性能有限,可以替换为Redis、MySQL等数据库存储数据,避免文件IO瓶颈导致的写入失败。

内容的提问来源于stack exchange,提问作者Three Year Old

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 21:24:01