Ajax-вызов компонента ColdFusion не возвращает данные

Я пытаюсь сделать вызов Ajax с помощью jQuery для моего компонента ColdFusion в QueryData.cfc.

Вот код QueryData.cfc:

<cfcomponent name="querydata" access="remote" hint="getting data from SQL database">
    <cffunction name="QueryData_Pt" access="remote" output="false" returntype="any" returnformat="JSON">
        <cfquery NAME="GrabData_Pt" DATASOURCE="#Application.PrimaryDataSource#" cachedWithin = "#CreateTimeSpan(0,0,1,0)#">
            //code;
        </cfquery>
        <cfloop query="GrabData_Pt">
            <cfset Pd_data=serializeJSON(GrabData_Pt)>
        </cfloop>
        <cfreturn GrabData_Pt>
    </cffunction>
    <cffunction name="QueryData_Pd" access="remote" returntype="any" returnformat="JSON">
        <cfquery NAME="GrabData_Pd" DATASOURCE="#Application.PrimaryDataSource#" cachedWithin = "#CreateTimeSpan(0,0,1,0)#">
            //code
        </cfquery>
        <cfloop query="GrabData_Pd">
            <cfset Pd_data=serializeJSON(GrabData_Pd)>
        </cfloop>
        <cfreturn GrabData_Pd>
    </cffunction>
    <cffunction name="QueryData_Rh" returntype="any" access="remote" returnformat="JSON">
        <cfquery NAME="GrabData_Rh" DATASOURCE="#Application.PrimaryDataSource#" cachedWithin = "#CreateTimeSpan(0,0,1,0)#">
            //somecode
        </cfquery>
        <cfloop query="GrabData_Rh">
            <cfset Rh_data=serializeJSON(GrabData_Rh)>
        </cfloop>
        <cfreturn Rh_data>
    </cffunction>
</cfcomponent>

У меня проблема в том, что ничего не возвращается. Я сбросил данные компонента, и запрос работает, как и ожидалось, так что это не так, но по какой-то причине данные передаются в мой файл .cfm. Я уверен, что что-то не так с jQuery, так что вот этот код:

var pt_var;
var pd_var;
var rh_var;
var pt_array = [];
var pd_array = [];
var rh_array = [];

$(function() {
    getdatafromquery();

    function getdatafromquery() {
      $.ajax({
        type: 'POST',
        contentType: "application/json; charset=utf-8", // this
        dataType: "json",
        url: 'QueryData.cfc',
        data: {
          method: 'QueryData_Pt'
        }
      }).done(function(pt_data) {
        pt_var = pt_data;

      });
    }

Затем я использую эти данные и рисую их с помощью highcharts. Я вижу, что через Google Chrome DevTools ничего не передается. Надеюсь, понятно, что я делаю не так. Я новичок в jQuery, Ajax и ColdFusion, поэтому для меня это огромная кривая обучения, ха-ха. Любая помощь действительно приветствуется!

РЕДАКТИРОВАТЬ:

Оказывается, я не сериализовал в json. Однако теперь, когда он передается, он передает каждую ячейку как отдельный массив. Вот пример:

DATA
:
Array(79)
0:[498]
1:[494]
2:[496]
3:[494]
4:[498]
5:[495]

person G.Rose    schedule 30.08.2018    source источник
comment
Поражает ли вызов AJAX ваш сервер ColdFusion? Вы видите, что функция вызывается? Кроме того, вам не нужно зацикливаться на запросе и serializeJSON() на каждой итерации. Вы можете просто сериализовать по возврату, например <cfreturn serializeJSON(GrabData_Pt)>.   -  person Miguel-F    schedule 30.08.2018
comment
Ваша функция, кажется, зацикливается на запросе и ничего с ним не делает. Вы хотите вернуть сериализованную строку JSON, а не объект запроса?   -  person haxtbh    schedule 30.08.2018
comment
Да, я в основном просто пытаюсь вернуть данные из запроса в формат JSON для вызова Ajax.   -  person G.Rose    schedule 30.08.2018
comment
Прямо сейчас я получаю сообщение об ошибке cant read property push of undefined. Я не вижу вызываемую функцию, я тоже не знаю, как   -  person G.Rose    schedule 30.08.2018
comment
Я бы просто придерживался запроса Ajax. Добавьте функцию отказа, так как она, скорее всего, не выполняет готовую часть. Используйте инструменты разработчика Google и устанавливайте точки останова в каждом разделе, чтобы увидеть, где он останавливается, и проверьте данные. Или в console.log возвращенные данные. Вероятно, запрос Ajax завершается ошибкой, потому что возвращается неверный JSON. Сериализуйте объект запроса при возврате.   -  person haxtbh    schedule 30.08.2018
comment
Фантастика! Это проанализировало правильные данные, но превратило каждую строку в свой собственный массив. Я обновил вопрос, чтобы показать некоторые результаты   -  person G.Rose    schedule 30.08.2018
comment
@ G.Rose G.Rose взгляните на документы serializejson. CF 11 и выше могут установить формат запроса, и вы можете установить его как struct.   -  person haxtbh    schedule 30.08.2018
comment
@haxtbh спасибо за помощь! По теме, не связанной с исходным вопросом, действительно ли createtimespan выполняет запрос каждую минуту, если мне это нужно?   -  person G.Rose    schedule 30.08.2018
comment
@ G.Rose это просто сообщает движку, как долго кэшировать запрос, прежде чем он снова запросит его из базы данных.   -  person haxtbh    schedule 30.08.2018
comment
@haxtbh в основном как дата эмиграции? Будет ли это обеспечивать обновление данных каждую минуту, если бы результаты вызова ajax добавлялись в массив?   -  person G.Rose    schedule 30.08.2018
comment
Кэширование не обновляет данные. Это просто гарантирует, что если запрос будет вызван снова в течение времени кеша, он не будет делать еще один доступ к базе данных для получения новых данных.   -  person Shawn    schedule 31.08.2018


Ответы (3)


То, как выводит ваш запрос, вот что я делаю; Я определил запрос, чтобы вы могли видеть, как он вызывается в цикле:

    <cffunction name="QueryData_Pt" access="remote" output="false" returntype="any" returnformat="JSON">
   <cfset retVal = ArrayNew(1)>

       <cfquery NAME="results" DATASOURCE="#Application.PrimaryDataSource#" cachedWithin = "#CreateTimeSpan(0,0,1,0)#">
        SELECT DEPARTMENTNAME,DEPTID,EMPLID,WORKPHONE,FULL_NAME,EMAIL_ADDRESS,LOCATION
    </cfquery>

      <cfloop query="results">
       <cfset temp = {} />
       <cfset temp['DEPARTMENTNAME']=DEPARTMENTNAME />
        <cfset temp['DEPARTMENTID']=DEPTID />
        <cfset temp['EMPLID']=EMPLID />
        <cfset temp['WORKPHONE']=WORKPHONE />
        <cfset temp['FULL_NAME']=FULL_NAME />
        <cfset temp['EMAIL_ADDRESS']=EMAIL_ADDRESS />
        <cfset temp['LOCATION']=LOCATION />
    <cfset ArrayAppend(retval, temp)>
    </cfloop>

    <cfset result = {} />
    <cfset result['items'] = retVal />
    <cfreturn result>
</cffunction>

В ajax я вызываю cfc, и в случае успеха я создаю var x=items.data, чтобы я мог вызывать данные таким образом x[0].DEPARTMENTNAME или, если в цикле for for (var i = 0; i < x.length; i++) x[i].DEPARTMENTNAME.

person Th0raxe    schedule 30.08.2018
comment
Благодарю вас! Я попробую - person G.Rose; 30.08.2018
comment
NP, дайте мне знать, если вам нужно, чтобы я опубликовал $.ajax - person Th0raxe; 30.08.2018
comment
Спасибо, я понял, хотя оказалось, что это довольно просто, ха-ха - person G.Rose; 30.08.2018
comment
Не забудьте локализовать все функциональные переменные. - person SOS; 30.08.2018

По моему опыту, использование удаленных методов .cfc создает некоторые проблемы. Их немного сложнее отлаживать, и они открывают векторы атак на ваши файлы .cfc, которые обычно содержат всю логику вашего приложения. ACF исправил несколько проблем безопасности с удаленными методами в файлах .cfc, и мне кажется неправильным разрешать удаленные вызовы в логике моего приложения.

Вместо этого я отделяю логику своего приложения от внешнего интерфейса. Интерфейсный код доступен из корневого веб-сайта (обычно /project_name/www/), в то время как другие уровни приложения будут расположены за пределами этого каталога, например. /project_name/cfusion/cfc/ или project_name/lib/stripe/stripe.cfc.

Альтернативный и эффективный подход к обработке ajax-запросов заключается в следующем: я использую файлы .cfm, расположенные внутри веб-корня, которые, в свою очередь, вызывают вызовы в мои CFC. Основным преимуществом является разделение кода и отладка.

Вот образец шаблона, я назову его /test.cfm:

<cfscript>
setting showdebugoutput=false;
header name="Content-Type" value="application/json";

try {

    param name="url.param1" type="numeric";
    param name="url.param2" type="numeric";

} catch (any e) {
    writeOutput(serializeJSON({
        "error": "Invalid request", 
        "errorCode": -1
    }));
    abort;
}

r = {
    "errorCode": 0,
    "error": ""
};

try {

    // create and call your cfc code here
    myCFC = createObject("cfc.something").init(url.param1);
    r = myCFC.doSomething();

} catch (any e) {

    // insert your own error handling here

    param name="errorCode" default=-1;

    r.errorCode = errorCode;
    r.error = e.message & " " & e.detail; 

}

writeOutput(serializeJSON(r));
</cfscript>

Затем из браузера вы можете сделать вызов ajax с помощью jquery следующим образом:

$.ajax({
    url: '/test.cfm',
    type: 'get',
    data: {
        param1: 4,
        param2: 90
    },
    dataType: 'json',
    success: function (json) {
        console.log(json);
    },
    error: function (xhr) {
        console.log(xhr);
        alert('an error occurred');
    }
});
person Redtopia    schedule 30.08.2018
comment
Я бы тоже принял это как ответ, спасибо за совет. Это очень полезно! - person G.Rose; 30.08.2018
comment
Очевидно, что область действия параметров в обработчике ajax изменится, если вы делаете запрос get или post. get запросы передают параметры в ваш обработчик ajax, используя область url, а post запросы передают параметры через область form. - person Redtopia; 30.08.2018
comment
это действительно сбило меня с толку, потому что один источник, из которого я читал, говорил, что POST - это то, как вы получаете информацию для своего ajax-вызова. Я знал, что методы HTTP универсальны, поэтому это немного замедлило меня, но спасибо! - person G.Rose; 30.08.2018

Подобно ответу Thor4x, я использую это

for (i in getQuery.columnList) {
  ret.q[i] = QueryColumnData(getQuery, i);
}

Я перебираю getQuery.columnList и использую QueryColumnData(). Результатом является объект JSON, структурированный почти как запрос холодного синтеза. За исключением того, что это структура массивов ajaxReturn.key[index], а не массив структур. ajaxReturn[index].key

Вы можете, как и они, указать столбцы вручную или использовать ЕСЛИ для фильтрации определенных ключей.

По крайней мере, в Lucee (и, вероятно, в ACF, поскольку Lucee стремится соответствовать ACF), мета-значения, такие как recordcount и columnList, сами по себе не находятся в query.columnList. Если вы хотите, чтобы они были скопированы, вам нужно только ручное назначение после цикла.

ret.q.recordcount = getQuery.recordcount;

person Regular Jo    schedule 30.08.2018