跨域Fetch调用PHP无报错但无返回数据问题求助
跨域Fetch请求无数据返回问题排查与解决
问题现象
- 同服务器场景:客户端
http://localhost:8888/myclient.html调用同主机PHP接口http://localhost:8888/myphp.php(MAMP环境),正常返回JSON数据。 - 跨域场景:客户端
http://127.0.0.1:5000调用上述PHP接口,无报错但完全没有数据返回。
客户端代码
<form target="_self" name="formulario" id="formulario"> <!-- Estamos usando lista desordenada para los campos de formulario Es también habitual hacerlo con los elementos de los menús de navegación --> <ul> <!-- H1 y H2 aquí van dentro de la etqueta UL para que no se solape con los campos, ya que este UL está en posición absoluta --> <h2>Envíanos tus datos</h2> <h1>Cubre el formulario</h1> <!-- Empiezan los campos de formulario --> <li> <!-- Campo obligatorio tipo texto--> <label for="nombre"><span class="required">*</span> Tu nombre</label><br> <input type="text" name="nombre" id="nombre" required> </li> <li> <!-- Campo tipo numérico--> <label for="edad">Tu edad</label><br> <input type="number" name="edad"> </li> <li> <!-- Campo obligatorio tipo Email--> <label for="email"><span class="required">*</span> Email</label><br> <input type="email" name="email" id="email" required> </li> <li> <!-- Campo tipo Tel (teléfono)--> Teléfono <br>(formato xxx yyy zzz):<br> <input type="tel" name="tel"> </li> <li> <!-- inputs tipo Radio-button Llevan el mismo nombre para que se reciba un solo dato. Es un solo campo con dos inputs que se marca además como obligatorio --> <span class="required">*</span> ¿Cómo vendrás al centro? <hr> <input type="radio" id="vehiculo" name="comoviene" value="vehiculo" required> <label for="vehiculo">Tengo vehículo</label><br> <input type="radio" id="andando" name="comoviene" value="andando"> <label for="andando">Voy andando</label> </li> <li> <!-- inputs tipo checkbox. Cada uno es un campo. --> ¿ Qué vehículos tienes ?<br> <input type="checkbox" id="coche" name="tipo" value="coche"> <label for="coche">Tengo coche</label><br> <input type="checkbox" id="moto" name="moto" value="moto"> <label for="moto">Tengo moto </label><br> <input type="checkbox" id="barco" name="barco" value="barco"> <label for="barco">Tengo barco</label> </li> <li> <!-- Campo tipo select, que crea un menú desplegable con las ociones --> ¿Qué curso quieres? <label for="curso">Elige uno</label> <select name="curso" id="curso"> <option value="">Elige uno...</option> <option value="HTML">HTML</option> <option value="CSS">CSS</option> <!-- Este sería el valor seleccionado por defecto --> <option value="JS" selected>JAVASCRIPT</option> </select> </li> <li> <!-- Botón de enviar. Es un input pero no envía valores, aunque tiene un value que es el texto que se ve en el botón, y por defecto (si no se pone) es "submit". --> <input type="submit" name="Enviar" value="Enviar"> </li> </ul> </form> <script> let formul = document.getElementById('formulario'); let path = "http://localhost:8888/CLASE/CURSO-IFCD0110/hola-background/"; formul.onsubmit = function (e) { e.preventDefault(); async function envio() { const datos = new FormData(e.target); let toSend = Object.fromEntries(datos); // console.log(toSend) let enviar = await fetch(path + 'form.php', { method: 'POST', /* * We also need to stringify the values, turn the * JavaScript object to a single string that is accepted * as JSON. So we are sending one string that contains * all our values */ mode: 'no-cors', body: JSON.stringify(toSend), headers: { 'Content-Type': 'application/json' // 'Content-Type': 'application/x-www-form-urlencoded', } }); let escribir = await enviar.json(); document.body.innerHTML = JSON.stringify(escribir) } envio(); } </script>
服务器端代码
<?php header("Access-Control-Allow-Origin: *"); header("Content-Type: application/json; charset=UTF-8"); header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, FETCH, OPTIONS"); header("Access-Control-Allow-Headers: Content-Type, Access- Control-Allow-Headers, Authorization, X-Requested-With"); $data = json_decode(file_get_contents('php://input'), true); echo json_encode($data); exit; ?>
问题根源与解决方案
1. 移除mode: 'no-cors'配置
mode: 'no-cors'会强制让浏览器限制JavaScript读取响应内容,即便服务器正常返回数据,前端也无法获取到。这是跨域场景无数据返回的核心原因。
修改后的fetch配置:
let enviar = await fetch(path + 'form.php', { method: 'POST', body: JSON.stringify(toSend), headers: { 'Content-Type': 'application/json' } });
2. 修复PHP服务器CORS配置
原PHP代码中Access-Control-Allow-Headers行存在换行错误,同时需要处理OPTIONS预检请求(跨域POST请求会先发送OPTIONS预检):
<?php header("Access-Control-Allow-Origin: *"); header("Content-Type: application/json; charset=UTF-8"); header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS"); header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"); // 处理OPTIONS预检请求,直接返回成功 if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; } $data = json_decode(file_get_contents('php://input'), true); echo json_encode($data); exit; ?>
3. 添加错误捕获与调试
在客户端代码中加入错误捕获,避免静默失败,方便排查问题:
async function envio() { try { const datos = new FormData(e.target); let toSend = Object.fromEntries(datos); let enviar = await fetch(path + 'form.php', { method: 'POST', body: JSON.stringify(toSend), headers: { 'Content-Type': 'application/json' } }); // 检查HTTP响应状态 if (!enviar.ok) { throw new Error(`请求失败,状态码: ${enviar.status}`); } let escribir = await enviar.json(); document.body.innerHTML = JSON.stringify(escribir); } catch (error) { console.error('请求出错:', error); document.body.innerHTML = `请求出错: ${error.message}`; } }
内容的提问来源于stack exchange,提问作者Luis Gar
相关产品推荐
相关产品推荐

