首页 > 解决方案 > jQuery ajax 调用无法从 CakePHP 3.8 读取 json 编码数据(获取一个空数组)

问题描述

我在读取我的 CakePHP3 API 返回的 json 编码数据以响应来自 jQuery 的 ajax 调用时遇到了一个奇怪的问题。我已经阅读了关于 stackoverflow 和其他地方的 20 多篇文章,以及人们遇到的常见问题,原因是错误的 dataType、contentType 或服务器没有从 ajax 获取数据。这些情况都不适用于这里(我尝试了不同的设置,但对我的问题没有影响)。

问题:

我的 ajax 调用向我的 CakePHP3 API 发送一些参数,API 正确获取参数并返回 CakePHP 实体的 json 编码数组(每个实体在发送回 ajax 调用之前添加了一个附加属性“available_yield”)。我在浏览器中使用直接 URL 获得了正确的输出(使用 json 验证器进行了检查,一切都很好),但是我的 ajax 调用(我在 Chrome devtools 中使用控制台和网络选项卡进行调查)显示了一个空数组,用于格式良好json。

我的调查表明,当我修改 CakePHP 实体时会出现问题。如果我从 API json 编码返回原始数据,jquery ajax 将获得正确的数据。但是当我修改任何实体时,jquery ajax 中的数组是空的。

从 CakePHP 调试显示,两个数组(未修改和已修改)看起来完全相同,除了添加的属性,即它们格式正确且在所有方面都可以,都在 json 中,在浏览器中都可以。但是jquery不接受修改后的json作为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');
            })
}

从 API 返回的 JSON 数据:

编辑: 可能很重要: 当我在浏览器中通过 URL 访问 API 时,它总是返回修改后的数据;看起来我的代码修改了 $matchingCrops 集中的实际实体。因此,如果将 $content 设置为 $matchingCrops 或 $cropsWithYieldInfo,浏览器中的结果总是相同的。但是通过 ajax 访问 API 时会有所不同:当 $content = json_encoded($matchingCrops) 我得到原始未修改的数据数组时,当 $content = json_encoded($cropsWithYieldInfo) 我得到一个空数组。

这真的很奇怪:为什么浏览器总是得到修改后的数组,而 ajax 得到一个或另一个???我知道如果我修改 $crop 实体,那么它会修改结果集中的实体,但我希望这对于浏览器和 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}]

标签: phpjsonajaxjquery-3cakephp-3.8

解决方案


$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()成功函数。

或者在这里使用 ajaxserializeArray()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;

推荐阅读