优化XMLHttpRequest:合并请求与数组处理方法
2025-09-28 10:18:30
0浏览
收藏
珍惜时间,勤奋学习!今天给大家带来《优化XMLHttpRequest:合并请求与数组处理技巧》,正文内容主要涉及到等等,如果你正在学习文章,或者是对文章有疑问,欢迎大家关注我!后面我会持续更新相关内容的,希望都能帮到正在学习的大家!
XMLHttpRequest批量数据发送的常见陷阱与优化策略
在Web开发中,通过XMLHttpRequest(XHR)异步向服务器发送数据是常见的需求。然而,当需要发送多批次或多种类型的数据时,不恰当的实现方式可能导致效率低下、数据丢失或逻辑错误。本教程将通过一个按键记录上传的案例,深入分析多请求发送的潜在问题,并提供一种更健壮、高效的优化方案。
问题分析:多XHR请求的挑战
原始实现尝试为不同的按键(W, A, D, S)分别维护缓存,并创建独立的FormData对象及XMLHttpRequest实例进行发送。这种方法存在以下几个核心问题:
- 条件判断过于严格: 数据发送逻辑被if (!keylog.sending && keylog.cacheW.length != 0)限制。这意味着只有当keylog.sending为false且keylog.cacheW中有数据时,才会触发发送。如果只有其他键(如A、D、S)被按下,W键的缓存为空,则任何数据都不会被发送。
- 并发控制不当: keylog.sending标志旨在防止重复发送。然而,当四个独立的XHR请求被同时发起时,每个请求的onload事件都会尝试将keylog.sending设置为false。这意味着第一个完成的请求会立即解锁发送机制,可能导致在其他请求仍在进行时,新的发送周期被错误地启动,从而引发竞态条件或数据覆盖。
- 效率低下: 为少量相关数据创建并管理多个独立的HTTP请求增加了网络开销(如TCP握手、HTTP头),并可能导致服务器资源占用增加。
- FormData与数组: 当使用FormData.append("key", array)时,JavaScript会将数组隐式转换为逗号分隔的字符串(例如["w", "!w"]会变成"w,!w"),而不是一个真正的数组结构。这要求后端进行额外的字符串解析,不如直接发送JSON数据来得清晰和可靠。
优化方案:合并请求与JSON数据传输
为了解决上述问题,最佳实践是将所有相关数据合并到一个请求中发送。这不仅提高了效率,也简化了并发控制逻辑。
1. JavaScript端:合并数据与单一XHR请求
我们将修改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);
关键改动点:
- 统一条件判断: hasData变量确保只要有任何键的缓存有数据,就尝试发送。
- 数据整合: 创建一个JavaScript对象dataToSend,将所有键的缓存作为其属性。
- JSON化数据: 使用JSON.stringify(dataToSend)将JavaScript对象转换为JSON字符串,这是通过XHR发送复杂数据结构的推荐方式。
- Content-Type头: 设置xhr.setRequestHeader("Content-Type", "application/json");告知服务器请求体是JSON格式。
- 单一XHR实例: 只创建一个XMLHttpRequest实例,避免了多个请求的并发管理复杂性。
- sending标志: keylog.sending标志的解锁只在单一请求完成或失败后发生,确保了正确的并发控制。
- 错误处理: 添加了xhr.onerror回调,用于处理网络层面的错误。
2. PHP后端:接收与解析JSON数据
服务器端需要相应地修改,以接收并解析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.']); ?>
关键改动点:
- 获取原始请求体: 使用file_get_contents('php://input')获取HTTP请求的原始POST体。当Content-Type为application/json时,数据不会自动填充到$_POST超全局变量中。
- 解析JSON: json_decode($json_data, true)将JSON字符串解析为PHP关联数组。
- 错误处理: 增加了对JSON解析失败的检查,并返回适当的HTTP状态码和错误信息。
- 数据访问: 通过$data['keysW']等方式访问客户端发送的数据。使用?? []为可能不存在的键提供默认值,增强代码健壮性。
- 文件写入模式: 将fopen模式从"w"(覆盖写入)改为"a"(追加写入),以确保每次发送的数据都能被记录,而不是覆盖之前的内容。同时,每次写入后添加换行符\n,便于阅读和后续处理。
- 文件权限: 移除或谨慎使用chmod,因为在Web环境下直接通过脚本设置文件权限可能存在安全风险,通常文件权限应由服务器配置或部署流程管理。
总结与最佳实践
通过上述优化,我们实现了一个更高效、更可靠的按键日志发送系统。总结以下几点最佳实践:
- 合并相关数据: 尽可能将逻辑上相关的数据合并到一个请求中发送,减少网络开销。
- 使用JSON进行数据交换: 对于结构化数据,JSON是Web API中最常用的数据交换格式。它易于JavaScript处理,并且大多数后端语言都有成熟的解析库。
- 正确设置Content-Type头: 当发送JSON数据时,务必设置Content-Type: application/json,以便服务器正确解析请求体。
- 后端验证与错误处理: 服务器端应始终验证接收到的数据,并对解析失败或数据缺失的情况进行适当的错误处理和响应。
- 并发控制: 在客户端使用标志位(如sending)来避免在同一时间发送多个重复或冲突的请求。
- 文件操作模式: 根据需求选择正确的文件打开模式("w"覆盖,"a"追加),并处理文件打开失败的情况。
- 安全性: 在生产环境中,应考虑更全面的安全措施,例如输入验证、身份认证、授权以及日志文件的安全存储和访问权限。
遵循这些原则将有助于构建更健壮、性能更优的Web应用程序。
以上就是《优化XMLHttpRequest:合并请求与数组处理方法》的详细内容,更多关于的资料请关注golang学习网公众号!

- 上一篇
- Python字典转JSON存储方法详解

- 下一篇
- Laravel批量任务finally未执行解决方法
查看更多
最新文章
-
- 文章 · php教程 | 5分钟前 |
- PHP模板设计技巧与使用方法
- 244浏览 收藏
-
- 文章 · php教程 | 41分钟前 | 依赖管理 Composer 自动加载 composer.lock composer.json
- PHPComposer是什么?项目依赖管理教程
- 189浏览 收藏
-
- 文章 · php教程 | 1小时前 |
- Laravelwith方法查询关联字段技巧
- 237浏览 收藏
-
- 文章 · php教程 | 1小时前 |
- PHP缓存优化技巧全解析
- 140浏览 收藏
-
- 文章 · php教程 | 1小时前 |
- Bootstrap标签页不切换?详细解决教程
- 272浏览 收藏
-
- 文章 · php教程 | 1小时前 |
- Laravel批量任务finally未执行解决方法
- 484浏览 收藏
-
- 文章 · php教程 | 2小时前 |
- PHP连接MongoDB实战教程
- 243浏览 收藏
-
- 文章 · php教程 | 2小时前 |
- PHP父类私有属性初始化方法
- 283浏览 收藏
-
- 文章 · php教程 | 2小时前 |
- PHP调用Dropbox列出文件夹内容方法
- 279浏览 收藏
查看更多
课程推荐
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 499次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
查看更多
AI推荐
-
- 潮际好麦-AI试衣
- 潮际好麦 AI 试衣平台,助力电商营销、设计领域,提供静态试衣图、动态试衣视频等全方位服务,高效打造高质量商品展示素材。
- 70次使用
-
- 蝉妈妈AI
- 蝉妈妈AI是国内首个聚焦电商领域的垂直大模型应用,深度融合独家电商数据库与DeepSeek-R1大模型。作为电商人专属智能助手,它重构电商运营全链路,助力抖音等内容电商商家实现数据分析、策略生成、内容创作与效果优化,平均提升GMV 230%,是您降本增效、抢占增长先机的关键。
- 154次使用
-
- 数说Social Research-社媒分析AI Agent
- 数说Social Research是数说故事旗下社媒智能研究平台,依托AI Social Power,提供全域社媒数据采集、垂直大模型分析及行业场景化应用,助力品牌实现“数据-洞察-决策”全链路支持。
- 128次使用
-
- 先见AI
- 先见AI,北京先智先行旗下企业级商业智能平台,依托先知大模型,构建全链路智能分析体系,助力政企客户实现数据驱动的科学决策。
- 129次使用
-
- 职优简历
- 职优简历是一款AI辅助的在线简历制作平台,聚焦求职场景,提供免费、易用、专业的简历制作服务。通过Markdown技术和AI功能,帮助求职者高效制作专业简历,提升求职竞争力。支持多格式导出,满足不同场景需求。
- 121次使用
查看更多
相关文章
-
- PHP技术的高薪回报与发展前景
- 2023-10-08 501浏览
-
- 基于 PHP 的商场优惠券系统开发中的常见问题解决方案
- 2023-10-05 501浏览
-
- 如何使用PHP开发简单的在线支付功能
- 2023-09-27 501浏览
-
- PHP消息队列开发指南:实现分布式缓存刷新器
- 2023-09-30 501浏览
-
- 如何在PHP微服务中实现分布式任务分配和调度
- 2023-10-04 501浏览