Преобразование вызова API из PHP и cURL в ColdFusion cfhttp

Я пытаюсь закодировать вызов API для компании, занимающейся онлайн-тестированием. Они предоставили пример вызова на PHP и cURL, который мне нужно реализовать в ColdFusion 11 с использованием <CFHTTP>. Пока моя попытка не удалась. Единственный ответ, который я получаю от их сервера/API:

Код состояния = "Ошибка соединения. Код состояния недоступен".

а также

ErrorDetail = "Исключение ввода-вывода: удаленный хост закрыл соединение во время рукопожатия".

Если бы это работало, я бы получил строку JSON с подробным описанием вычисленных оценок. Обратите внимание, что в приведенном ниже коде я изменил несколько значений из соображений безопасности, кроме того, что это исходный код. Любые предложения или комментарии будут высоко оценены, спасибо.

Вот код ColdFusion/cfhttp:

<cfoutput>
<cfset sdata = [
    {
        "customerid" = "ACompany",
        "studentid" = "test",
        "form" = "X",
        "age" = "18.10",
        "norms" = "grade",
        "grade" = "2"
    },
    {
        "scores" = [
        {"subtest"="math","score"="34"},
        {"score"="23","subtest"="lang"},
        {"score"="402","subtest"="rcomp"}
        ]
    }

]>
<!--- create JSON string for request --->
<cfset jsdata = serializeJSON(sdata)>
<!--- make the call --->
<cfhttp method="Get" url="https://www.APIwebsite.php" timeout="10" result="varx">
     <cfhttpparam type="header" name="Content-Type" value = "application/json; charset=utf-8"/>
     <cfhttpparam type="body" value = "#jsdata#"/>
     <cfhttpparam type="header" name="Authorization" value="AuthCode"/> 
     <cfhttpparam type="header" name="Content-Length" value = "#len(jsdata)#"/>
</cfhttp>

<!--- show results --->
cfhttp return status code: [#varx.statusCode#]<br> 
cfhttp return fileContent: [#varx.fileContent#]<br>
</cfoutput>

Вот код PHP/cURL:

<?php
    $data = array
    (
    "customerid" => "ACompany",
    "studentid" => "test",
    "scoringtype" => 2,
    "form" => "X",
    "age" => "18.10",
    "norms" => 'grade',
    "grade" => '2',
    "scores" => array(
        array("subtest" => "math", "score" => "34"),
        array("subtest" => "lang", "score" => "23"),
        array("subtest" => "rcomp", "score" => "402")
    ));

    $url = 'https://www.APIwebsite.php';
    $json_string = json_encode($data);

   $headers = array (
        "Content-Type: application/json; charset=utf-8",
        "Content-Length: " .strlen($json_string),
        "Authorization: AuthCode"
    );

    $channel = curl_init($url);
    curl_setopt($channel, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($channel, CURLOPT_CUSTOMREQUEST, "GET");
    curl_setopt($channel, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($channel, CURLOPT_POSTFIELDS, $json_string);
    curl_setopt($channel, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($channel, CURLOPT_CONNECTTIMEOUT, 10);

    $response = curl_exec($channel); // execute the request
    $statusCode = curl_getInfo($channel, CURLINFO_HTTP_CODE);
    $error = curl_error($channel);
    curl_close($channel);

    http_response_code($statusCode);
    if ( $statusCode != 200 ){
        echo "Status code: {$statusCode} \n".$error;
    } else {
        $data = json_decode($response,true);
        foreach ($data as $key => $value) {
            echo nl2br($key . ': ' . $value . "\n");
        }
    }
?>

person LocoRolly    schedule 25.11.2019    source источник
comment
Это может иметь или не иметь отношение к проблеме, но код CF не включает значение типа подсчета очков.   -  person Dan Bracuk    schedule 25.11.2019
comment
Спасибо за предложение, Дэн. Я не уверен, что вы имеете в виду под типом оценки. Появляется ли что-то подобное в коде cURL или вы думаете, что его нужно добавить в код cf, чтобы он был эквивалентен?   -  person LocoRolly    schedule 25.11.2019
comment
Также ваш метод неверен, либо отправьте как сообщение в теле, либо как получите в URL-адресе, прямо сейчас вы отправляете как получение в теле, что не имеет смысла. Если API поддерживает сообщение, я бы предложил использовать сообщение, иначе вы может закончиться проблемой слишком длинного URL-адреса   -  person Tofandel    schedule 25.11.2019
comment
@LocoRolly Он просто имел в виду, что в опубликованном вами примере в curl у вас есть скорингтип в полезной нагрузке, но не в cfhttp   -  person Tofandel    schedule 25.11.2019
comment
Какой URL-адрес вы используете? Вероятно, проблема именно в этой конкретной ошибке. Действителен ли сертификат ssl? Я вижу, у вас есть проверка ssl, установленная в false в curl, но cfhttp не имеет такой функции   -  person Tofandel    schedule 25.11.2019
comment
Спасибо Тофандель за все ваши комментарии. В коде curl у меня есть curlopt_customrequest, получайте только полезную нагрузку в curlopt_postfields, $json_string. Мне они кажутся противоречивыми, но человек, с которым я общаюсь в компании, говорит, что это ПОЛУЧЕНИЕ. Так что я в замешательстве. Я знаю, что у меня нет cfhttpparam, эквивалентного верифицирующему узлу. Знаете, что это может быть?   -  person LocoRolly    schedule 26.11.2019
comment
Я также считаю, что это может быть проблема на их сервере, поскольку мой вызов, похоже, не доходит до API. Когда я просто помещаю URL-адрес в браузер без данных или заголовков, я получаю ответ от API. Это, конечно, ответ об ошибке, но, по крайней мере, сервер не заблокировал вызов.   -  person LocoRolly    schedule 26.11.2019
comment
Давайте продолжим обсуждение в чате.   -  person Tofandel    schedule 26.11.2019


Ответы (1)


Сначала убедитесь, что указанный вами URL-адрес правильный (я знаю, что это для примера, но .php не является допустимым расширением доменного имени) и что сертификат SSL действителен.

Если оба верны, вы должны изменить метод запроса на POST для отправки данных json через тело

Согласно https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html#GET

Клиент не должен генерировать тело в запросе GET. Полезная нагрузка, полученная в запросе GET, не имеет определенной семантики, не может изменить значение или цель запроса и может привести к тому, что некоторые реализации отклонят запрос и закроют соединение из-за его потенциальной возможности атаки контрабандой запросов.

В cfhttp есть параметр charset, поэтому вам не нужно отправлять его в заголовке

Вот код, который должен работать

<cfset sdata = [
    {
        "customerid" = "ACompany",
        "studentid" = "test",
        "form" = "X",
        "age" = "18.10",
        "scoringtype" = 2,
        "norms" = "grade",
        "grade" = "2"
    },
    {
        "scores" = [
            {"subtest"="math","score"="34"},
            {"score"="23","subtest"="lang"},
            {"score"="402","subtest"="rcomp"}

        ]
    }

]>
<!--- create JSON string for request --->
<cfset jsdata = serializeJSON(sdata)>
<!--- make the call --->
<cfhttp method="post" charset="utf-8" url="https://api.website.com/" timeout="10" result="varx">
     <cfhttpparam type="header" name="Content-Type" value="application/json"/>
     <cfhttpparam type="header" name="Authorization" value="AuthCode"/> 
     <cfhttpparam type="header" name="Content-Length" value="#len(jsdata)#"/>
     <cfhttpparam type="body" value="#jsdata#"/>
</cfhttp>

<!--- show results --->
<cfoutput>
cfhttp return status code: [#varx.statusCode#]<br>
cfhttp return fileContent: [#varx.fileContent#]<br>
</cfoutput>
person Tofandel    schedule 25.11.2019
comment
Еще раз спасибо за все ваши усилия, очень признателен. Я попробовал код, который вы предложили, с тем же результатом. Признаюсь, однако, что я довольно невежественен. SSL-сертификаты. Как я могу узнать, что это проблема? Может быть, мне следует просто больше узнать о них, так что указатель или ссылка? Спасибо - person LocoRolly; 26.11.2019
comment
Если вы можете получить доступ к URL-адресу с помощью HTTPS, не получая предупреждения о безопасности, то, скорее всего, это не проблема, и проверка ssl не требуется. - person Tofandel; 26.11.2019
comment
Спасибо. Я провел еще несколько тестов и обнаружил, что, хотя API напрямую отвечает на гиперссылку в шаблоне или окне URL-адреса браузера (конечно, с ошибкой), я получаю ошибку подключения при попытке той же простой ссылки через cfhttp. Что бы ни случилось с моим кодом, это кажется проблемой само по себе. Я видел сообщения об этом, которые вращаются вокруг сертификатов безопасности. Любые комментарии или предложения приветствуются. Также хочу сказать, что это было очень полезно. Несмотря на то, что я еще не решил проблему, я получил подтверждение, что мой код по крайней мере синтаксически верен. Спасибо - person LocoRolly; 27.11.2019
comment
Вы пробовали с URL-адресом, например, google.com? Просто чтобы убедиться, что это не проблема на вашем сервере - person Tofandel; 27.11.2019
comment
Спасибо, я вернулся. На самом деле у меня есть сервер на моей машине для целей разработки, без ssl. Затем у меня есть два удаленных сайта на том же сервере, где используется приложение, один для тестирования, другой для производства. Итак, у меня есть испытательный стенд для создания вызова API и получения ответа от ssl-сервера, что я и сделал. На данный момент я почти уверен, что на стороне целевой компании есть какая-то настройка или протокол, который отклоняет мой вызов до того, как он будет обработан их API. Могут быть и другие проблемы, но сначала их нужно решить, и мне нужен их вклад, чтобы продолжить. - person LocoRolly; 01.12.2019