У меня странная проблема с чтением закодированных данных json, возвращаемых моим API CakePHP3 в ответ на вызов ajax из jQuery. Я уже прочитал более 20 сообщений в stackoverflow и других местах, а также обычные проблемы, с которыми люди сталкивались, когда из-за неправильного типа данных, типа контента или из-за того, что сервер не получал данные от ajax. Ни один из этих случаев здесь не применим (я пробовал разные настройки, но это не повлияло на мою проблему).
Проблема:
Мой вызов ajax отправляет некоторые параметры моему API CakePHP3, API правильно получает параметры и возвращает закодированный json массив объектов CakePHP (каждый объект имеет дополнительное свойство «доступный_выход», добавленное перед его отправкой обратно в вызов ajax). Я получаю правильный вывод, используя прямой URL-адрес в браузере (проверил его с помощью валидаторов json, все хорошо), но мой вызов ajax (для исследования я использовал вкладки консоли и сети в инструментах разработки Chrome) показывает пустой массив для правильно сформированного json.
Мое расследование показало, что проблема возникает, когда я изменяю сущности CakePHP. Если я верну исходные данные из API в кодировке json, jquery ajax получит правильные данные. Но когда я изменяю какой-либо объект, массив в jquery ajax пуст.
Отладка из CakePHP показывает, что оба массива (немодифицированный и модифицированный) выглядят абсолютно одинаково, за исключением добавленного свойства, т.е. они правильно сформированы и во всех отношениях ОК, оба в json, оба ОК в браузере. Но модифицированный не принимается jquery как json.
Решение на данный момент выглядит так: не изменяйте свои данные! Но это то, что мы делаем на сервере перед отправкой соответствующих и обработанных данных клиенту, не так ли?
У кого-нибудь была похожая проблема?
Прикрепляю свой код:
Функция API CakePHP:
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, возвращенные из API:
РЕДАКТИРОВАТЬ: Может быть важно: Когда я обращаюсь к API через URL-адрес в браузере, он всегда возвращает измененные данные; похоже, мой код изменяет фактические объекты в наборе $matchingCrops. Таким образом, если установить для $content значение $matchingCrops или $cropsWithYieldInfo, результат в браузере всегда будет одинаковым. Но отличается при доступе к API через ajax: когда $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}]
return $this->response->withType("application/json")->withStringBody(json_encode($result));
вместоreturn $this->response;
- person Dlk   schedule 07.02.2020