React+PHP登录功能POST请求无法接收参数问题排查
React + PHP登录功能PHP端无法接收请求参数的问题解决
问题描述
- 登录功能与注册功能实现逻辑一致,但PHP端始终无法接收请求参数
- Chrome浏览器中请求显示被重定向,Firefox浏览器中因请求数据为空抛出错误
- 注册功能中通过
file_get_contents("php://input", true)可正常获取请求数据,但登录功能中该方法返回空值
相关代码
Fetch钩子函数
import React, { useEffect, useState } from 'react' function useFetch(url, options) { const [data, setData] = useState(null); const [loading, setLoading] = useState(null); const [error, setError] = useState(null); useEffect(() => { if(!url) return; setLoading(true); setTimeout(() => { (async function fetchData() { try { const response = await fetch(url, options); if(!response.ok) throw new Error(); const data = await response.json(); setData(data); setLoading(false) } catch(e) { setLoading(false) setError(e.message); } })() }, 3000);; }, [url]) return [data, loading, error]; } export default useFetch
登录组件
import React, { useState } from 'react' import classes from '../../assets/styles/Main.module.css' import useFetch from '../../hooks/useFetch'; function Login() { const [userInputs, setUserInputs] = useState({ "username": "nadim", "email": "nadim.aa@hotmail.com", }) const [url, setUrl] = useState(null); const [data, loading, error] = useFetch(url, { method: "POST", body: JSON.stringify(userInputs), mode: "no-cors", }); const submitHandler = () => { setUrl("http://localhost/whatsinit/api/user"); } console.log(data, loading, error); return ( <div className={classes.login}> <h2>Login to your account</h2> <input className={classes.login_username} type='text' placeholder='Username or email'/> <input className={classes.singup_password} type='password' placeholder='Password'/> <button onClick={submitHandler} className={classes.register_button}>login</button> </div> ) } export default Login
PHP代码
<?php header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Methods: GET, POST"); header("Access-Control-Allow-Headers: Content-Type"); include_once '../../config/Database.php'; class User { private $table = 'users'; private $connection; private $username; public function __construct($connection, $user_inputs) { $this->connection = $connection; if(!is_null($user_inputs)) { $this->username = $user_inputs['username']; $this->email = $user_inputs['email']; } } public function readUser() { try { $command = "SELECT * FROM $this->table WHERE (username = ? OR email = ?);"; $stmt = $this->connection->stmt_init(); $stmt->prepare($command); $stmt->bind_param("ss", $this->username, $this->email); if(!$stmt->execute()) { throw new Exception("Could not get user"); } $response = $stmt->get_result(); return $response; } catch (\Throwable $th) { echo json_encode($th->getMessage()); } $this->connection->close(); } } $database = new Database(); $connection = $database->connect(); $user = new User($connection, json_decode(file_get_contents("php://input", true))); try { $result = $user->readUser(); $nums = $result->num_rows; $json_items = array(); if($nums) { while($row = $result->fetch_assoc()) { extract($row); array_push($json_items, $row); } } else { throw new Exception("Not Registered!"); } echo json_encode($json_items); } catch (\Throwable $th) { echo json_encode($th->getMessage()); exit(); } ?>
解决方案
1. 移除mode: "no-cors"配置
no-cors模式会限制浏览器请求行为,无法发送Content-Type: application/json头,也无法读取响应内容,直接导致PHP端无法解析JSON请求体。修改登录组件的fetch配置:
const [data, loading, error] = useFetch(url, { method: "POST", body: JSON.stringify(userInputs), headers: { "Content-Type": "application/json" // 显式指定请求格式 } // 移除 mode: "no-cors" });
2. 修复useFetch钩子的依赖与延迟问题
- 原钩子仅监听
url变化,options参数更新时不会触发重新请求,需将options加入依赖数组 - 不必要的
setTimeout会延迟请求,且可能导致状态更新异常,直接移除
修改后的useFetch钩子:
import React, { useEffect, useState } from 'react' function useFetch(url, options) { const [data, setData] = useState(null); const [loading, setLoading] = useState(null); const [error, setError] = useState(null); useEffect(() => { if(!url) return; setLoading(true); (async function fetchData() { try { const response = await fetch(url, options); if(!response.ok) throw new Error(`HTTP错误!状态码: ${response.status}`); const data = await response.json(); setData(data); setLoading(false) } catch(e) { setLoading(false) setError(e.message); } })() }, [url, options]) // 添加options到依赖数组 return [data, loading, error]; } export default useFetch
3. 修复PHP的JSON解析逻辑
json_decode(file_get_contents("php://input", true))默认返回对象,而User构造函数使用数组方式访问属性,需将第二个参数设为true转为关联数组:
$user = new User($connection, json_decode(file_get_contents("php://input", true), true));
4. 绑定登录输入框与状态
原登录组件的输入框未与userInputs绑定,提交的是固定测试数据,添加onChange事件同步输入值:
function Login() { const [userInputs, setUserInputs] = useState({ "username": "", "email": "", "password": "" // 补充password字段 }) // ...其余代码 return ( <div className={classes.login}> <h2>Login to your account</h2> <input className={classes.login_username} type='text' placeholder='Username or email' value={userInputs.username} onChange={(e) => setUserInputs(prev => ({...prev, username: e.target.value}))} /> <input className={classes.singup_password} type='password' placeholder='Password' value={userInputs.password} onChange={(e) => setUserInputs(prev => ({...prev, password: e.target.value}))} /> <button onClick={submitHandler} className={classes.register_button}>login</button> </div> ) }
5. 完善PHP的CORS预检请求处理
添加OPTIONS请求的处理逻辑,避免浏览器预检请求报错:
// 处理OPTIONS预检请求 if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Methods: GET, POST"); header("Access-Control-Allow-Headers: Content-Type"); exit(); } // 原有的CORS头与业务逻辑 header("Access-Control-Allow-Origin: *"); header("Access-Control-Allow-Methods: GET, POST"); header("Access-Control-Allow-Headers: Content-Type"); include_once '../../config/Database.php'; // ...其余代码
内容的提问来源于stack exchange,提问作者Nadim
相关产品推荐
相关产品推荐

