向服务器传输并存储数据时如何避免丢失?短间隔传输丢数据解决方案
数据丢失原因
- 前端层面:代码全局复用同一个
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
相关产品推荐
相关产品推荐

