AJAX发送JSON请求到PHP控制器接收为null,xdebug断点有值访问报错
问题原因及修复方案
- 1. json_decode返回类型不匹配+无错误校验
默认json_decode()返回的是stdClass对象而非数组,如果你用数组下标(如$newData['Search'])访问对象属性会直接报错;如果请求体为空解析失败,json_decode()会返回null,此时访问下标就会触发你遇到的Trying to access array offset on value of type null错误。
修复代码:
$rawData = file_get_contents("php://input"); // 第二个参数设为true 直接返回关联数组 $newData = json_decode($rawData, true); // 增加解析结果校验 if (json_last_error() !== JSON_ERROR_NONE || is_null($newData)) { // 自定义错误处理逻辑 show_error('请求参数解析错误', 400); }
2. CodeIgniter框架CSRF校验拦截JSON格式请求
你用的是CI框架自带的CSRF防护,默认CSRF校验只会读取$_POST全局变量中的令牌值,你传的是application/json格式的请求体,框架无法识别到请求中的CSRF令牌,会直接拦截请求,导致进入控制器时php://input已经为空,解析结果为null。
有两种修复方式可选:- 方式一(推荐):调整AJAX请求格式,不用JSON传参,用默认表单格式,框架可直接识别参数和CSRF令牌,无需修改后端逻辑:
$.ajax({ type: 'POST', url:'<?=base_url()?>news/support', // 移除contentType配置,用默认的application/x-www-form-urlencoded data: data, // 直接传JS对象,无需JSON.stringify });后端控制器直接用框架方法取值即可:
$search = $this->input->post('Search');- 方式二:重写CI核心CSRF校验类,支持JSON请求的令牌校验,在
application/core目录下新建MY_Security.php:
class MY_Security extends CI_Security { public function csrf_verify() { if ($_SERVER['REQUEST_METHOD'] === 'POST' && empty($_POST)) { $raw = file_get_contents('php://input'); $decoded = json_decode($raw, true); if (!is_null($decoded)) { $_POST = $decoded; } } return parent::csrf_verify(); } }3. php://input重复读取导致为空
php://input是只读流,整个请求生命周期内只能读取一次,如果框架核心逻辑已经读过一次,你在控制器中再次读取会直接返回空。如果必须使用JSON传参,建议在全局位置统一解析一次请求体后存入公共变量,避免重复读取流。
Xdebug断点调试时能拿到值,是因为调试触发时请求已经通过了CSRF校验,且只读取了一次输入流;正常运行时要么CSRF校验被拦截,要么流被提前读取,才会出现解析结果为null的情况。
内容的提问来源于stack exchange,提问作者Chris S
相关产品推荐
相关产品推荐

