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

多个XMLHttpRequest请求无法向后端发送数据如何排查解决

问题排查与修复方案

核心错误点

  • 发送条件逻辑错误:原代码仅当W按键缓存有值时才会触发发送逻辑,用户仅按下A/S/D按键时不会执行任何请求
  • 多请求逻辑混乱:同时发起4个XHR请求,每个请求仅携带单个按键的参数,每个请求结束都会提前解锁,锁机制完全失效;且单个请求到达PHP后,另外三个按键参数不存在,会直接清空对应文件的内容
  • 数据格式错误:FormData.append() 传入数组时会自动转为逗号分隔的字符串,PHP侧直接json_encode后存储格式不符合预期
  • 文件写入模式错误:PHP用w模式打开文件,每次写入都会清空之前的所有记录,无法累计保存按键数据

修复后的代码

JavaScript代码

var keylog = {
  // (A) 设置与属性
  cacheW: [], // 按键临时存储
  cacheA: [],
  cacheD: [],
  cacheS: [],
  delay: 500, // 向服务端发送数据的间隔(毫秒)
  sending: false, // 同一时间仅允许一个上传请求

  // (B) 初始化
  init: function() {
    // (B1) 捕获按键动作
    window.addEventListener("keydown", function(evt) {
      switch(evt.key) {
        case "w": keylog.cacheW.push(evt.key); break;
        case "a": keylog.cacheA.push(evt.key); break;
        case "d": keylog.cacheD.push(evt.key); break;
        case "s": keylog.cacheS.push(evt.key); break;
      }
    });

    window.addEventListener("keyup", function(evt) {
      switch(evt.key) {
        case "w": keylog.cacheW.push("!" + evt.key); break;
        case "a": keylog.cacheA.push("!" + evt.key); break;
        case "d": keylog.cacheD.push("!" + evt.key); break;
        case "s": keylog.cacheS.push("!" + evt.key); break;
      }
    });

    // (B2) 定时向服务端发送按键数据
    window.setInterval(keylog.send, keylog.delay);
  },

  // (C) AJAX发送按键数据
  send: function() {
    // 只要任意一个缓存有数据就发送
    const hasData = keylog.cacheW.length || keylog.cacheA.length || keylog.cacheD.length || keylog.cacheS.length;
    if (!keylog.sending && hasData) {
      // (C1) 加锁,直到本次请求完成再解锁
      keylog.sending = true;

      // (C2) 所有数据整合到同一个FormData里单次发送
      var data = new FormData();
      // 数组转JSON字符串再上传,避免自动转成逗号分隔的字符串
      data.append("keysW", JSON.stringify(keylog.cacheW));
      data.append("keysA", JSON.stringify(keylog.cacheA));
      data.append("keysD", JSON.stringify(keylog.cacheD));
      data.append("keysS", JSON.stringify(keylog.cacheS));
      
      // 清空缓存
      keylog.cacheW = [];
      keylog.cacheA = [];
      keylog.cacheD = [];
      keylog.cacheS = [];

      // (C3) 单个AJAX请求发送所有数据
      var xhr = new XMLHttpRequest();
      xhr.open("POST", "index4.php");
      xhr.onload = function() {
        keylog.sending = false; // 请求完成解锁
        // console.log(this.response); 
      };
      xhr.send(data);
    }
  }
};
window.addEventListener("DOMContentLoaded", keylog.init);

PHP代码

<?php
// 先判断参数是否存在,不存在就不处理对应文件,避免报错
if (isset($_POST['keysW'])) {
    $keysW = $_POST['keysW'];
    $keylogW = 'player2KeylogW.txt';
    // 用a模式追加写入,不会清空之前的内容,需要覆盖则换回w
    $writeKeylogW = fopen($keylogW, "a") or die("Unable to open W file!");
    // 直接写入拿到的JSON字符串即可,不需要再json_encode
    fwrite($writeKeylogW, $keysW . PHP_EOL);
    fclose($writeKeylogW);
    chmod($keylogW , 0755);
}

if (isset($_POST['keysA'])) {
    $keysA = $_POST['keysA'];
    $keylogA = 'player2KeylogA.txt';
    $writeKeylogA = fopen($keylogA, "a") or die("Unable to open A file!");
    fwrite($writeKeylogA, $keysA . PHP_EOL);
    fclose($writeKeylogA);
    chmod($keylogA , 0755);
}

if (isset($_POST['keysD'])) {
    $keysD = $_POST['keysD'];
    $keylogD = 'player2KeylogD.txt';
    $writeKeylogD = fopen($keylogD, "a") or die("Unable to open D file!");
    fwrite($writeKeylogD, $keysD . PHP_EOL);
    fclose($writeKeylogD);
    chmod($keylogD , 0755);
}

if (isset($_POST['keysS'])) {
    $keysS = $_POST['keysS'];
    $keylogS = 'player2KeylogS.txt';
    $writeKeylogS = fopen($keylogS, "a") or die("Unable to open S file!");
    fwrite($writeKeylogS, $keysS . PHP_EOL);
    fclose($writeKeylogS);
    chmod($keylogS , 0755);
}
?>

补充说明

浏览器本身允许向同一个服务端地址发送多个请求,你遇到的问题完全是业务逻辑错误导致的。如果修复后仍有异常,可以打开浏览器控制台的「网络」标签,查看XHR请求的状态、请求参数、返回值快速定位问题。

内容的提问来源于stack exchange,提问作者seriously

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 07:36:06