跨域场景下PHP如何向JavaScript Fetch API返回响应?
跨域POST请求下PHP无法返回响应的解决方法
问题核心原因
- 客户端设置
mode: 'no-cors',该模式会限制浏览器读取响应内容,即便后端正常返回数据; - 后端未配置跨域资源共享(CORS)响应头,跨域请求被浏览器拦截;
- 后端else分支仅设置状态码,未返回JSON格式响应,客户端无法解析;
- 客户端发送JSON格式数据,但PHP用
$_POST接收(仅支持application/x-www-form-urlencoded或multipart/form-data格式),导致数据解析异常。
一、修正客户端Fetch代码
移除mode: 'no-cors',并确保请求体为JSON字符串:
fetch(this.url, { method: 'POST', body: JSON.stringify(this.getFormValues()), headers: { "Accept": "application/json", 'Content-Type': 'application/json' } }) .then(resp => { if (!resp.ok) throw new Error(resp.statusText); return resp.json(); }) .then(data => { console.log(data); if (data.ok) this.Metrics.setSent(); }) .then(() => { this.Metrics.setSent(); this.Metrics.dismiss(); }) .catch(error => { console.log("错误: ", error); this.Metrics.dismiss(); });
二、修正PHP后端代码
添加CORS头、正确解析JSON请求体、确保所有分支返回JSON响应,并修复SQL注入风险:
<?php include_once('database/connection.php'); // 配置CORS响应头,生产环境建议替换*为具体允许的域名 header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: POST'); header('Access-Control-Allow-Headers: Content-Type, Accept'); header('Content-Type: application/json'); // 解析JSON格式请求体 $input = json_decode(file_get_contents('php://input'), true); if (!$input) { http_response_code(400); echo json_encode(['ok' => false, 'status' => 400, 'message' => '无效的JSON数据']); exit; } // 提取请求参数,添加默认值避免未定义索引错误 $ip = $input["ip"] ?? ''; $city = $input["city"] ?? ''; $state = $input["state"] ?? ''; $country = $input["country"] ?? ''; $category = $input["category"] ?? ''; // 使用预处理语句查询IP是否已注册,防止SQL注入 $ip_query = "SELECT * FROM registers WHERE `ip` = ?"; $stmt = mysqli_prepare($conn, $ip_query); mysqli_stmt_bind_param($stmt, 's', $ip); mysqli_stmt_execute($stmt); $ip_result = mysqli_stmt_get_result($stmt); $ip_check = mysqli_fetch_assoc($ip_result); if (!$ip_check) { // 预处理语句插入新数据 $new_query = "INSERT INTO `registers` (`ip`, `city`, `state`, `country`, `category`, `created`) VALUES (?, ?, ?, ?, ?, '2022-07-21 00:00:01')"; $stmt = mysqli_prepare($conn, $new_query); mysqli_stmt_bind_param($stmt, 'sssss', $ip, $city, $state, $country, $category); $new_create = mysqli_stmt_execute($stmt); // 根据插入结果返回响应 if ($new_create) { $response = ['ok' => true, 'status' => 200, 'message' => '注册成功']; http_response_code(200); } else { $response = ['ok' => false, 'status' => 500, 'message' => '注册失败']; http_response_code(500); } echo json_encode($response); } else { // IP已注册时返回JSON响应,用409表示资源冲突更合理 http_response_code(409); echo json_encode(['ok' => false, 'status' => 409, 'message' => '该IP已注册']); }
关键修改说明
- 移除
mode: 'no-cors':该模式仅适用于无需处理响应的场景,会屏蔽浏览器对响应内容的读取权限; - JSON字符串转换:客户端需将表单对象转为JSON字符串,确保后端能正确解析;
- 解析JSON请求体:PHP通过
php://input读取原始请求数据,再解析为数组; - CORS头配置:服务器明确允许跨域请求,避免浏览器拦截响应;
- 全分支JSON响应:无论成功或失败,都返回标准JSON格式,保证客户端可正常解析;
- 预处理语句:彻底避免SQL注入风险,提升代码安全性。
内容的提问来源于stack exchange,提问作者Luiz Cavalcante
相关产品推荐
相关产品推荐

