
在Web开发中,通过XMLHttpRequest(XHR)异步向服务器发送数据是常见的需求。然而,当需要发送多批次或多种类型的数据时,不恰当的实现方式可能导致效率低下、数据丢失或逻辑错误。本教程将通过一个按键记录上传的案例,深入分析多请求发送的潜在问题,并提供一种更健壮、高效的优化方案。
原始实现尝试为不同的按键(W, A, D, S)分别维护缓存,并创建独立的FormData对象及XMLHttpRequest实例进行发送。这种方法存在以下几个核心问题:
为了解决上述问题,最佳实践是将所有相关数据合并到一个请求中发送。这不仅提高了效率,也简化了并发控制逻辑。
我们将修改keylog.send方法,使其收集所有缓存的按键数据,将其封装为一个JSON对象,然后通过单个XMLHttpRequest实例发送。
var keylog = {
// (A) SETTINGS & PROPERTIES
cacheW: [], // TEMP STORAGE FOR KEY PRESSES
cacheA: [],
cacheD: [],
cacheS: [],
delay: 500, // HOW OFTEN TO SEND DATA TO SERVER
sending: false, // ONLY 1 UPLOAD ALLOWED AT A TIME
// (B) INITIALIZE
init: function() {
// (B1) CAPTURE KEY STROKES
window.addEventListener("keydown", function(evt) {
const key = evt.key;
if (key === "w") keylog.cacheW.push(key);
else if (key === "a") keylog.cacheA.push(key);
else if (key === "d") keylog.cacheD.push(key);
else if (key === "s") keylog.cacheS.push(key);
});
window.addEventListener("keyup", function(evt) {
const key = evt.key;
if (key === "w") keylog.cacheW.push("!" + key);
else if (key === "a") keylog.cacheA.push("!" + key);
else if (key === "d") keylog.cacheD.push("!" + key);
else if (key === "s") keylog.cacheS.push("!" + key);
});
// (B2) SEND KEYSTROKES TO SERVER
window.setInterval(keylog.send, keylog.delay);
},
// (C) AJAX SEND KEYSTROKES
send: function() {
// 检查是否有任何缓存数据需要发送
const hasData = keylog.cacheW.length > 0 ||
keylog.cacheA.length > 0 ||
keylog.cacheD.length > 0 ||
keylog.cacheS.length > 0;
if (!keylog.sending && hasData) {
keylog.sending = true; // 锁定,直到本次发送完成
// 1. 收集所有数据
const dataToSend = {
keysW: keylog.cacheW,
keysA: keylog.cacheA,
keysD: keylog.cacheD,
keysS: keylog.cacheS
};
// 2. 清空缓存
keylog.cacheW = [];
keylog.cacheA = [];
keylog.cacheD = [];
keylog.cacheS = [];
// 3. 创建 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
xhr.open("POST", "index4.php");
// 设置请求头,告知服务器发送的是JSON数据
xhr.setRequestHeader("Content-Type", "application/json");
// 4. 定义请求完成时的回调
xhr.onload = function() {
if (xhr.status >= 200 && xhr.status < 300) {
// console.log("数据发送成功:", this.response);
} else {
// console.error("数据发送失败:", xhr.status, this.statusText);
// 错误处理:可以考虑将未成功发送的数据重新放回缓存或记录错误
}
keylog.sending = false; // 解锁
};
// 5. 定义请求错误时的回调
xhr.onerror = function() {
// console.error("网络请求错误");
keylog.sending = false; // 解锁
};
// 6. 发送数据 (将JavaScript对象转换为JSON字符串)
xhr.send(JSON.stringify(dataToSend));
}
}
};
window.addEventListener("DOMContentLoaded", keylog.init);关键改动点:
服务器端需要相应地修改,以接收并解析JSON格式的请求体。
<?php
// 获取原始POST请求体
$json_data = file_get_contents('php://input');
// 将JSON字符串解码为PHP关联数组
$data = json_decode($json_data, true); // true 表示解码为关联数组
// 检查解码是否成功以及数据是否存在
if (json_last_error() !== JSON_ERROR_NONE || !is_array($data)) {
http_response_code(400); // Bad Request
echo json_encode(['status' => 'error', 'message' => 'Invalid JSON data received.']);
exit();
}
// 从解码后的数据中提取按键日志
$keysW = $data['keysW'] ?? []; // 使用 ?? 操作符提供默认空数组,避免未定义错误
$keysA = $data['keysA'] ?? [];
$keysD = $data['keysD'] ?? [];
$keysS = $data['keysS'] ?? [];
// 定义文件路径
$keylogW_file = 'player2KeylogW.txt';
$keylogA_file = 'player2KeylogA.txt';
$keylogD_file = 'player2KeylogD.txt';
$keylogS_file = 'player2KeylogS.txt';
// 写入W键日志
if (!empty($keysW)) {
if ($writeKeylogW = fopen($keylogW_file, "a")) { // 使用 "a" 模式追加写入
fwrite($writeKeylogW, json_encode($keysW) . "\n"); // 写入JSON并换行
fclose($writeKeylogW);
} else {
error_log("Unable to open file for writing: " . $keylogW_file);
}
}
// 写入A键日志
if (!empty($keysA)) {
if ($writeKeylogA = fopen($keylogA_file, "a")) {
fwrite($writeKeylogA, json_encode($keysA) . "\n");
fclose($writeKeylogA);
} else {
error_log("Unable to open file for writing: " . $keylogA_file);
}
}
// 写入D键日志
if (!empty($keysD)) {
if ($writeKeylogD = fopen($keylogD_file, "a")) {
fwrite($writeKeylogD, json_encode($keysD) . "\n");
fclose($writeKeylogD);
} else {
error_log("Unable to open file for writing: " . $keylogD_file);
}
}
// 写入S键日志
if (!empty($keysS)) {
if ($writeKeylogS = fopen($keylogS_file, "a")) {
fwrite($writeKeylogS, json_encode($keysS) . "\n");
fclose($writeKeylogS);
} else {
error_log("Unable to open file for writing: " . $keylogS_file);
}
}
// 设置文件权限(如果需要,但通常在创建时已由umask决定)
// chmod($keylogW_file, 0755); // 注意:生产环境不建议直接设置0755给文件,尤其是写入文件
// chmod($keylogA_file, 0755);
// chmod($keylogD_file, 0755);
// chmod($keylogS_file, 0755);
// 返回成功响应
echo json_encode(['status' => 'success', 'message' => 'Key logs saved.']);
?>关键改动点:
通过上述优化,我们实现了一个更高效、更可靠的按键日志发送系统。总结以下几点最佳实践:
遵循这些原则将有助于构建更健壮、性能更优的Web应用程序。
以上就是优化XMLHttpRequest数据发送:合并请求与正确处理数组数据的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号