XMLHttpRequest同步请求返回值异常及TypeError错误排查求助
问题解决:XHR函数无法返回值及null读取length错误
问题根源
- 同步XHR事件执行顺序偏差:你使用了同步XHR,但
onreadystatechange事件的触发时机滞后于items = products.length的执行,此时products仍为初始值null,直接读取length就会抛出Cannot read properties of null (reading 'length')错误。 - SQL注入风险:PHP代码直接拼接用户输入到SQL语句中,存在严重安全漏洞。
修复方案
方案1:修正同步XHR逻辑(不推荐,易阻塞页面)
同步请求完成后,可直接读取XHR响应,无需依赖onreadystatechange事件:
function fetch_api_products(query) { var xhr = new XMLHttpRequest(); var url = 'products.php?act=search_products&query=' + encodeURI(query); xhr.open('GET', url , false); xhr.send(); if (xhr.status === 200) { var products = xhr.responseText; items = products.length; return products; } else { items = 0; return null; } }
方案2:改用异步XHR+Promise(推荐,无页面阻塞)
同步XHR会阻塞浏览器主线程,异步方式更友好:
function fetch_api_products(query) { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); // 单独编码query参数更严谨 var url = `products.php?act=search_products&query=${encodeURIComponent(query)}`; xhr.open('GET', url , true); xhr.onload = () => { xhr.status === 200 ? resolve(xhr.responseText) : reject(new Error(`请求失败:${xhr.status}`)); }; xhr.onerror = () => reject(new Error('网络请求出错')); xhr.send(); }); } // 调用示例 fetch_api_products('你的查询关键词') .then(products => { // 建议转成JSON对象处理,而非直接用字符串长度 const productList = JSON.parse(products); items = productList.length; alert(JSON.stringify(productList)); // 后续业务逻辑写在这里 }) .catch(err => { console.error(err); items = 0; });
修复PHP的SQL注入漏洞
使用PDO预处理语句,彻底避免注入风险:
$dbh = new PDO( 'mysql:host=' . $config['db_server'] . ';dbname=' . $config['db_name'], $config['db_user'], $config['db_password'] ); $dbh->exec("set names utf8mb4"); if(isset($_GET['query'])){ $query = $_GET['query']; // 预处理语句+占位符 $stmt = $dbh->prepare("SELECT id,name,barcode,price FROM products WHERE name LIKE ? OR barcode LIKE ?"); $likePattern = '%' . $query . '%'; // 绑定参数,指定类型 $stmt->bindParam(1, $likePattern, PDO::PARAM_STR); $stmt->bindParam(2, $likePattern, PDO::PARAM_STR); $stmt->execute(); echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC)); }
额外提示
- 拿到响应后,记得用
JSON.parse()将字符串转为JSON对象,这样productList.length才是实际的商品数量,而非响应字符串的长度。 - 尽量减少全局变量(比如
items)的使用,可将数据封装在函数或回调内部,降低代码耦合度。
内容的提问来源于stack exchange,提问作者Hakeem
相关产品推荐
相关产品推荐

