使用Fetch API与XHR同步POST传JS变量至PHP时$_POST为空的问题
问题
我正在本地WordPress站点开发功能,需求是用户提交表单数据后,由PHP处理修改并实现无刷新展示结果。尝试了JavaScript的fetch()和XHR两种异步POST方法,点击提交按钮后虽能成功请求到PHP文件,但print_r($_POST)始终返回空数组。试过传递FormData对象、JSON字符串、普通字符串,均无法将变量传入PHP的POST变量中。另外,不解为何PHP脚本中的echo内容无法显示在页面上,希望得到原因解释和解决帮助。
相关代码如下:
HTML代码
<html> <div> <section> <form id="testForm" action="file.php" method="post"> <input type="text" id="testInput" name="testInput"> <input type="button" id="testBtn" name="testBtn" value="Test Button"> </form> </section> </div> </html>
JavaScript代码
let testButton = document.getElementById("testBtn"); let tef = document.getElementById("testForm"); var variableValue = tef.value; var formData = new FormData(tef); var xhr = new XMLHttpRequest(); xhr.open("POST", "/file.php", true); xhr.open("GET", "/file.php", true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE) { if (xhr.status === 200) { console.log(xhr.responseText); } else { console.error("Error:", xhr.status); } } }; testButton.onclick = function(){ testButton.style.color = "red"; // confirm click fetch("/file.php", { method: "POST", body: JSON.stringify({'testForm':variableValue}) }) .then(res => res.text()) .then(txt => { alert(txt); }) .catch(e => console.error(e)); xhr.send(formData); xhr.onload = function(){ testButton.style.color = "purple"; // initial confirmation XHR method has worked }; }
PHP代码
<?php echo "This works!"; //this is visible in alert or console but never the page print_r($_POST); // always returns an empty array so far ?>
问题分析与解决方法
一、$_POST为空的原因及修复
XHR请求的致命错误:重复调用
open()方法
你先后调用了xhr.open("POST", ...)和xhr.open("GET", ...),第二次调用会完全覆盖第一次的请求配置,最终XHR发送的是GET请求,自然不会有POST数据。删除多余的xhr.open("GET", "/file.php", true);即可。FormData初始化时机错误
页面加载时就创建formData,此时输入框还没有用户输入的内容,所以FormData是空的。需要把FormData的创建移到按钮点击事件内部,确保获取到最新的表单数据:testButton.onclick = function(){ // ...其他代码 var formData = new FormData(tef); // 移到点击事件内 xhr.send(formData); // ...其他代码 }Fetch的JSON数据未被PHP解析
用JSON.stringify()发送数据时,PHP默认不会自动将其解析到$_POST中(因为默认Content-Type不是application/x-www-form-urlencoded)。有两种解决方式:- 改用FormData发送Fetch请求:
fetch("/file.php", { method: "POST", body: new FormData(tef) }) - 在PHP中手动解析JSON:
$jsonData = json_decode(file_get_contents('php://input'), true); print_r($jsonData); // 可获取到JSON格式的请求数据
- 改用FormData发送Fetch请求:
表单值获取错误
tef.value是表单元素本身的value属性,而非输入框的内容。要获取输入框的值,应该用document.getElementById("testInput").value。
二、PHP的echo内容无法显示在页面上的原因
你使用的是异步请求(fetch/XHR),这类请求是在后台静默发送的,服务器返回的响应只会回到JS的回调函数里(比如fetch的then、XHR的onreadystatechange),不会自动替换页面内容。如果要把结果显示在页面上,需要手动操作DOM:
// 先在HTML中添加结果展示容器:<div id="result"></div> // Fetch回调中更新页面 .then(txt => { document.getElementById("result").innerHTML = txt; }) // XHR回调中更新页面 if (xhr.status === 200) { document.getElementById("result").innerHTML = xhr.responseText; }
三、修复后的完整示例代码
调整后的JavaScript
let testButton = document.getElementById("testBtn"); let tef = document.getElementById("testForm"); let resultContainer = document.getElementById("result"); var xhr = new XMLHttpRequest(); // 仅配置一次POST请求 xhr.open("POST", "/file.php", true); // 发送FormData时无需手动设置Content-Type,浏览器会自动处理 xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE) { if (xhr.status === 200) { resultContainer.innerHTML = xhr.responseText; console.log(xhr.responseText); } else { console.error("Error:", xhr.status); } } }; testButton.onclick = function(){ testButton.style.color = "red"; // 方案1:用Fetch发送FormData fetch("/file.php", { method: "POST", body: new FormData(tef) }) .then(res => res.text()) .then(txt => { alert(txt); resultContainer.innerHTML = txt; }) .catch(e => console.error(e)); // 方案2:用XHR发送FormData(测试时建议注释掉其中一种请求) // let formData = new FormData(tef); // xhr.send(formData); // xhr.onload = function(){ // testButton.style.color = "purple"; // }; }
调整后的PHP
<?php echo "This works!<br>"; // 处理FormData提交的情况 print_r($_POST); // 如果需要处理JSON提交,保留以下代码 // $jsonData = json_decode(file_get_contents('php://input'), true); // echo "<br>JSON数据:<br>"; // print_r($jsonData); ?>
补充结果容器的HTML
<html> <div> <section> <form id="testForm" action="file.php" method="post"> <input type="text" id="testInput" name="testInput"> <input type="button" id="testBtn" name="testBtn" value="Test Button"> </form> <!-- 新增结果展示容器 --> <div id="result"></div> </section> </div> </html>
内容的提问来源于stack exchange,提问作者First Last

