jQuery ajax 调用无法从 CakePHP 3.8 读取 json 编码数据(获取一个空数组)
jQuery ajax call can't read json encoded data from CakePHP 3.8 (gets an empty array)
我在读取由我的 CakePHP3 API 编辑的 json 编码数据时遇到了一个奇怪的问题,以响应来自 jQuery 的 ajax 调用。我已经阅读了 20 多篇关于 Whosebug 和其他地方的帖子,以及人们遇到的常见问题,这些问题是由于错误的数据类型、内容类型或者是服务器没有从 ajax 获取数据。 None 这些情况适用于此处(我尝试了不同的设置,但对我的问题没有影响)。
问题:
我的 ajax 调用将一些参数发送到我的 CakePHP3 API,API 正确获取参数并且 return 是 CakePHP 的 json 编码数组实体(每个实体在发送回 ajax 调用之前添加了一个额外的 属性 'available_yield')。我在浏览器中使用直接 URL 得到了正确的输出(用 json 验证器检查过,一切都很好),但是我的 ajax 调用(我在 Chrome devtools to investigate) 为格式正确的 json.
显示一个空数组
我的调查显示问题发生在我修改 CakePHP 实体时。如果我return原始数据由APIjson编码,jqueryajax得到正确的数据。但是当我修改任何实体时,jquery ajax 中的数组是空的。
从 CakePHP 调试显示,除了添加的 属性 之外,两个数组(未修改的和修改过的)看起来完全一样,即它们在所有方面都格式正确且正常,都在 json , 在浏览器中都可以。但是修改后的一个不被 jquery 接受为 json.
目前的解决方案似乎是:不要修改您的数据!但这就是我们在将相关和处理后的数据发送到客户端之前在服务器上所做的,不是吗?
有没有人遇到过类似的问题?
我附上我的代码:
CakePHP API 函数:
function myFunction(){
$params = $this->getRequest()->getQueryParams();
//debug($params);
$componentReference = $params['component_reference'];
$componentTypeId = $params['component_type_id'];
$matchingCrops = $this->Crops->find()->select(['id', 'grower_name', 'bulk'])->where(['reference' => $componentReference]);
$cropsWithYieldInfo = []; //to hold modify crop
foreach($matchingCrops as $crop){
$availableYield = $this->Crops->calculateAvailableYield($crop->id); //returns a string
if(isset($availableYield) && !empty($availableYield)){
$crop->available_yield = number_format($availableYield,1); //tried $crop['available_yield'] as well, same result
$cropsWithYieldInfo[] = $crop;
}
}
// debug($cropsWithYieldInfo);
// debug($matchingCrops);
//$content = json_encode($cropsWithYieldInfo); // <<-- changing to $matchingCrops makes ajax see the array, but the array does not have my calculated data
$content = json_encode($matchingCrops);
$this->response = $this->response->withStringBody($content);
$this->response = $this->response->withType('json');
$this->autoRender = false;
return $this->response;
}
我的AJAX:
function myAjax(){
$.ajax({
type: 'GET',
url: url,
//contentType: "application/json",
dataType: "json"
})
.done(function (data) {
console.log(data);
})
.fail(function (data) {
console.log('AJAX call to /'+errMsg+' function failed');
})
}
JSON 数据 return 来自 API:
编辑:
可能很重要:
当我在浏览器中通过 URL 访问 API 时,它总是 return 修改数据;看起来我的代码修改了 $matchingCrops 集中的实际实体。因此,如果将 $content 设置为 $matchingCrops 或 $cropsWithYieldInfo,则浏览器中的结果始终相同。但是当通过 ajax 访问 API 时不同:当 $content = json_encoded($matchingCrops) 我得到原始的未修改的数据数组,当 $content = json_encoded( $cropsWithYieldInfo) 我得到一个空数组。
这真的很奇怪:为什么浏览器总是得到修改后的数组,而 ajax 得到一个或另一个???我知道如果我修改 $crop 实体然后它会修改结果集中的实体,但我希望这对于浏览器和 ajax 调用都是一致的。
编辑:
我尝试了一个稍微修改过的代码来查看克隆实体是否会有任何不同,但唯一的区别是现在浏览器得到了我期望发生的事情(原始未修改的数组或修改过的数组)并且它与 ajax 得到。但这并不能解决问题(如果数组被修改,ajax 仍然得到空数组)。
foreach($matchingCrops as $crop){
$modCrop = clone $crop;
$availableYield = $this->Crops->calculateAvailableYield($crop->id); //returns a string
if(isset($availableYield) && !empty($availableYield)){
$modCrop->available_yield = number_format($availableYield,1); //tried $crop['available_yield'] as well, same result
$cropsWithYieldInfo[] = $modCrop;
}
}
已修改(ajax 将此作为空数组获取;浏览器始终从 API 获取):
[{"id":12345,"grower_name":"XYZ","bulk":false,"available_yield":"4.1"},{"id":23456,"grower_name":null,"bulk":true,"available_yield":"190.0"}]
未修改(ajax 正确理解):
[{"id":12345,"grower_name":"XYZ","bulk":false},{"id":23456,"grower_name":null,"bulk":true}]
天啊……找到了!好吧,这很尴尬,但我仍然要 post 把它作为一个教训,并作为对其他人的警告:如果你晚上遇到无法解决的问题,就回家吧好好睡一觉,早上再出发!
问题原因:
1) 我的计算函数实际上返回的是浮点数而不是字符串,我正在检查是否为空,所以当它返回 0 时,代码没有将 'available_yield' 属性 添加到$crop 实体(因为负责它的代码行也在错误的地方!应该在 if 块之外)
此时我还是'alright, but I should get consistent behaviour both in the browser and in the ajax call!!!',除非...
2) 我没有注意到我在浏览器检查和 ajax 调用中使用了不同的 ID,所以计算机是正确的...:-/
一直在学习...
- 仔细检查每一行并调试所有可能的变量!
- 仔细检查您的测试数据!
运行正常的代码版本:
function myFunction(){
$params = $this->getRequest()->getQueryParams();
//debug($params);
$componentReference = $params['component_reference'];
$componentTypeId = $params['component_type_id'];
$matchingCrops = $this->Crops->find()->select(['id', 'grower_name', 'bulk'])->where(['reference' => $componentReference]);
$cropsWithYieldInfo = []; //to hold modify crop
$cropsWithYieldString = '';
foreach($matchingCrops as $crop){
$availableYield = $this->Crops->calculateAvailableYield($crop->id); //returns a float not string!
if(isset($availableYield)){ //<<- that was the cause of the problem; !empty(float) will ignore 0, just check if it's set
$crop->available_yield = number_format($availableYield,1);
}
$cropsWithYieldInfo[] = $crop;
}
// debug($cropsWithYieldInfo);
// debug($matchingCrops);
$content = json_encode($cropsWithYieldInfo);
//$this->response = $this->response->withStringBody($content);
//$this->response = $this->response->withType('application/json');
$this->autoRender = false;
//return $this->response;
//more concisely
return $this->response->withType('application/json')->withStringBody($content);
}
感谢你们抽出宝贵的时间,你们让我专注于寻找解决方案。
$array = ['foo'=>'bar'];
$this->set([
'response' => $array,
'_serialize' => 'response',
]);
$this->Request->renderAs($this, 'json');
而且我会序列化 ajax!因此,您不需要对对象进行字符串化,您可以直接将其用于数据 属性.
$.ajax({
type: 'POST',
url: url,
data: {YourArray: YourVariables},
success: function(data) {
alert(data);
}
});
您可以在此处找到更多信息:https://api.jquery.com/serialize/
让我们看看您的 ajax 您需要将值从数组传递到 ajax 以获取您尝试执行的每个值的响应 +errMsg+
。
您的 ajax 在失败和成功中应该如下所示:
失败:function( jqXHR, Status, errMsg) {
然后你可以显示像 console.log('AJAX call to /'+errMsg+' function failed');
这样的响应
$.ajax({
type: "GET",
url: url,
data: {
title: $(value[0]).val(),
description: $(value[1]).val()
},
success: function (data) {
if(data === "success") {
// do something with data or whatever other data on success
console.log('success');
} else if(data === "error") {
// do something with data or whatever other data on error
console.log('error');
}
}
});
要显示指定的错误,您需要在成功函数中传递 title = $(value[0]).val()
。
或在此处使用 ajax serializeArray()
和 each()
示例 https://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_ajax_serializearray
从 CakePHP 3.4 开始,使用应该使用
$content = json_encode($matchingCrops);
return $this->response->withType("application/json")->withStringBody($content);
而不是这个
$content = json_encode($matchingCrops);
$this->response = $this->response->withStringBody($content);
$this->response = $this->response->withType('json');
$this->autoRender = false;
return $this->response;
我在读取由我的 CakePHP3 API 编辑的 json 编码数据时遇到了一个奇怪的问题,以响应来自 jQuery 的 ajax 调用。我已经阅读了 20 多篇关于 Whosebug 和其他地方的帖子,以及人们遇到的常见问题,这些问题是由于错误的数据类型、内容类型或者是服务器没有从 ajax 获取数据。 None 这些情况适用于此处(我尝试了不同的设置,但对我的问题没有影响)。
问题:
我的 ajax 调用将一些参数发送到我的 CakePHP3 API,API 正确获取参数并且 return 是 CakePHP 的 json 编码数组实体(每个实体在发送回 ajax 调用之前添加了一个额外的 属性 'available_yield')。我在浏览器中使用直接 URL 得到了正确的输出(用 json 验证器检查过,一切都很好),但是我的 ajax 调用(我在 Chrome devtools to investigate) 为格式正确的 json.
显示一个空数组我的调查显示问题发生在我修改 CakePHP 实体时。如果我return原始数据由APIjson编码,jqueryajax得到正确的数据。但是当我修改任何实体时,jquery ajax 中的数组是空的。
从 CakePHP 调试显示,除了添加的 属性 之外,两个数组(未修改的和修改过的)看起来完全一样,即它们在所有方面都格式正确且正常,都在 json , 在浏览器中都可以。但是修改后的一个不被 jquery 接受为 json.
目前的解决方案似乎是:不要修改您的数据!但这就是我们在将相关和处理后的数据发送到客户端之前在服务器上所做的,不是吗?
有没有人遇到过类似的问题?
我附上我的代码:
CakePHP API 函数:
function myFunction(){
$params = $this->getRequest()->getQueryParams();
//debug($params);
$componentReference = $params['component_reference'];
$componentTypeId = $params['component_type_id'];
$matchingCrops = $this->Crops->find()->select(['id', 'grower_name', 'bulk'])->where(['reference' => $componentReference]);
$cropsWithYieldInfo = []; //to hold modify crop
foreach($matchingCrops as $crop){
$availableYield = $this->Crops->calculateAvailableYield($crop->id); //returns a string
if(isset($availableYield) && !empty($availableYield)){
$crop->available_yield = number_format($availableYield,1); //tried $crop['available_yield'] as well, same result
$cropsWithYieldInfo[] = $crop;
}
}
// debug($cropsWithYieldInfo);
// debug($matchingCrops);
//$content = json_encode($cropsWithYieldInfo); // <<-- changing to $matchingCrops makes ajax see the array, but the array does not have my calculated data
$content = json_encode($matchingCrops);
$this->response = $this->response->withStringBody($content);
$this->response = $this->response->withType('json');
$this->autoRender = false;
return $this->response;
}
我的AJAX:
function myAjax(){
$.ajax({
type: 'GET',
url: url,
//contentType: "application/json",
dataType: "json"
})
.done(function (data) {
console.log(data);
})
.fail(function (data) {
console.log('AJAX call to /'+errMsg+' function failed');
})
}
JSON 数据 return 来自 API:
编辑: 可能很重要: 当我在浏览器中通过 URL 访问 API 时,它总是 return 修改数据;看起来我的代码修改了 $matchingCrops 集中的实际实体。因此,如果将 $content 设置为 $matchingCrops 或 $cropsWithYieldInfo,则浏览器中的结果始终相同。但是当通过 ajax 访问 API 时不同:当 $content = json_encoded($matchingCrops) 我得到原始的未修改的数据数组,当 $content = json_encoded( $cropsWithYieldInfo) 我得到一个空数组。
这真的很奇怪:为什么浏览器总是得到修改后的数组,而 ajax 得到一个或另一个???我知道如果我修改 $crop 实体然后它会修改结果集中的实体,但我希望这对于浏览器和 ajax 调用都是一致的。
编辑: 我尝试了一个稍微修改过的代码来查看克隆实体是否会有任何不同,但唯一的区别是现在浏览器得到了我期望发生的事情(原始未修改的数组或修改过的数组)并且它与 ajax 得到。但这并不能解决问题(如果数组被修改,ajax 仍然得到空数组)。
foreach($matchingCrops as $crop){
$modCrop = clone $crop;
$availableYield = $this->Crops->calculateAvailableYield($crop->id); //returns a string
if(isset($availableYield) && !empty($availableYield)){
$modCrop->available_yield = number_format($availableYield,1); //tried $crop['available_yield'] as well, same result
$cropsWithYieldInfo[] = $modCrop;
}
}
已修改(ajax 将此作为空数组获取;浏览器始终从 API 获取):
[{"id":12345,"grower_name":"XYZ","bulk":false,"available_yield":"4.1"},{"id":23456,"grower_name":null,"bulk":true,"available_yield":"190.0"}]
未修改(ajax 正确理解):
[{"id":12345,"grower_name":"XYZ","bulk":false},{"id":23456,"grower_name":null,"bulk":true}]
天啊……找到了!好吧,这很尴尬,但我仍然要 post 把它作为一个教训,并作为对其他人的警告:如果你晚上遇到无法解决的问题,就回家吧好好睡一觉,早上再出发!
问题原因:
1) 我的计算函数实际上返回的是浮点数而不是字符串,我正在检查是否为空,所以当它返回 0 时,代码没有将 'available_yield' 属性 添加到$crop 实体(因为负责它的代码行也在错误的地方!应该在 if 块之外)
此时我还是'alright, but I should get consistent behaviour both in the browser and in the ajax call!!!',除非...
2) 我没有注意到我在浏览器检查和 ajax 调用中使用了不同的 ID,所以计算机是正确的...:-/
一直在学习...
- 仔细检查每一行并调试所有可能的变量!
- 仔细检查您的测试数据!
运行正常的代码版本:
function myFunction(){
$params = $this->getRequest()->getQueryParams();
//debug($params);
$componentReference = $params['component_reference'];
$componentTypeId = $params['component_type_id'];
$matchingCrops = $this->Crops->find()->select(['id', 'grower_name', 'bulk'])->where(['reference' => $componentReference]);
$cropsWithYieldInfo = []; //to hold modify crop
$cropsWithYieldString = '';
foreach($matchingCrops as $crop){
$availableYield = $this->Crops->calculateAvailableYield($crop->id); //returns a float not string!
if(isset($availableYield)){ //<<- that was the cause of the problem; !empty(float) will ignore 0, just check if it's set
$crop->available_yield = number_format($availableYield,1);
}
$cropsWithYieldInfo[] = $crop;
}
// debug($cropsWithYieldInfo);
// debug($matchingCrops);
$content = json_encode($cropsWithYieldInfo);
//$this->response = $this->response->withStringBody($content);
//$this->response = $this->response->withType('application/json');
$this->autoRender = false;
//return $this->response;
//more concisely
return $this->response->withType('application/json')->withStringBody($content);
}
感谢你们抽出宝贵的时间,你们让我专注于寻找解决方案。
$array = ['foo'=>'bar'];
$this->set([
'response' => $array,
'_serialize' => 'response',
]);
$this->Request->renderAs($this, 'json');
而且我会序列化 ajax!因此,您不需要对对象进行字符串化,您可以直接将其用于数据 属性.
$.ajax({
type: 'POST',
url: url,
data: {YourArray: YourVariables},
success: function(data) {
alert(data);
}
});
您可以在此处找到更多信息:https://api.jquery.com/serialize/
让我们看看您的 ajax 您需要将值从数组传递到 ajax 以获取您尝试执行的每个值的响应 +errMsg+
。
您的 ajax 在失败和成功中应该如下所示:
失败:function( jqXHR, Status, errMsg) {
然后你可以显示像 console.log('AJAX call to /'+errMsg+' function failed');
$.ajax({
type: "GET",
url: url,
data: {
title: $(value[0]).val(),
description: $(value[1]).val()
},
success: function (data) {
if(data === "success") {
// do something with data or whatever other data on success
console.log('success');
} else if(data === "error") {
// do something with data or whatever other data on error
console.log('error');
}
}
});
要显示指定的错误,您需要在成功函数中传递 title = $(value[0]).val()
。
或在此处使用 ajax serializeArray()
和 each()
示例 https://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_ajax_serializearray
从 CakePHP 3.4 开始,使用应该使用
$content = json_encode($matchingCrops);
return $this->response->withType("application/json")->withStringBody($content);
而不是这个
$content = json_encode($matchingCrops);
$this->response = $this->response->withStringBody($content);
$this->response = $this->response->withType('json');
$this->autoRender = false;
return $this->response;