При интеграции 1С 7.7 с современными веб-сервисами и REST API разработчики часто сталкиваются с форматом JSON. В платформе 1С:Предприятие 7.7 нет встроенных средств сериализации и десериализации JSON, поэтому классическим подходом стало использование внешнего скриптового движка MSScriptControl.ScriptControl на языке JScript. Однако при получении объемного ответа от сервера система может внезапно завершить работу без генерации понятного описания ошибки. Разберем по шагам, почему возникает сбой и какими способами можно стабильно разобрать большие структуры данных.
Посмотрим на типовой пример кода, используемый для разбора JSON в среде 1С 7.7:
ScrptCtrl = СоздатьОбъект("MSScriptControl.ScriptControl");
ScrptCtrl.Language = "jscript";
КодНаJScript =
"function parseJSON(strJSON) {
| var tmpFunc = (new Function('return(' + strJSON + ');'))();
| return(tmpFunc);
|}
|function aGet(Array, index) {
| return(Array[index]);
|}
|function oValueByKey(Obj, key) {
| return(Obj[key]);
|}
|function oSize(Obj) {
| var size = 0, key;
| for (key in Obj) {
| if (Obj.hasOwnProperty(key)) size++;
| }
| return(size);
|}
|function eType(Element) {
| if (Element instanceof Array) {
| return('array');
| } else {
| return(typeof(Element));
| }
|}";
ScrptCtrl.AddCode(КодНаJScript);
Объект = ScrptCtrl.Run("parseJSON", СтрокаОтвета);
При небольших объемах данных (до нескольких десятков килобайт) данный скрипт отрабатывает корректно. Но как только переменная СтрокаОтвета содержит тяжелый массив данных, строка ScrptCtrl.Run("parseJSON", СтрокаОтвета) приводит к аварийному закрытию приложения (Crash / Access Violation).
Проанализируем технические факторы, которые вызывают аварийное завершение:
IDispatch платформа выполняет преобразование в двухбайтовую строку Unicode (BSTR). При передаче строк большого объема (от нескольких сотен килобайт) во внутреннем буфере механизма OLE платформы переполняется память, что вызывает мгновенный сбой процесса 1cv7.exe.new Function('return(' + strJSON + ');') заставляет движок JScript компилировать весь объемный JSON как фрагмент исполняемого программного кода. Для больших списков или глубокой вложенности парсер скрипта исчерпывает выделенный стек синтаксического анализатора (Stack Overflow).Чтобы избежать ошибки передачи огромной строки из 1С в COM-объект, передадим заботу о чтении файла самому скрипту. В метод передается только путь к файлу на диске, который читается напрямую средствами Windows Script Host.
Рассмотрим реализацию чтения файла через поток ADODB.Stream, что одновременно гарантирует правильную работу с кодировкой UTF-8:
КодНаJScript =
"function parseJSONFromFile(filePath) {
| var stream = new ActiveXObject('ADODB.Stream');
| stream.Type = 2; // adTypeText
| stream.Charset = 'utf-8';
| stream.Open();
| stream.LoadFromFile(filePath);
| var strJSON = stream.ReadText();
| stream.Close();
| var tmpFunc = (new Function('return(' + strJSON + ');'))();
| return(tmpFunc);
|}";
ScrptCtrl = СоздатьОбъект("MSScriptControl.ScriptControl");
ScrptCtrl.Language = "jscript";
ScrptCtrl.AddCode(КодНаJScript);
// Сохраняем ответ во временный файл
ИмяФайла = КаталогВременныхФайлов() + "response.json";
// (запись ответа в файл средствами 1С или прямое сохранение из HTTP-запроса)
Объект = ScrptCtrl.Run("parseJSONFromFile", ИмяФайла);
Данный подход полностью решает проблему падения ядра 1С при вызове метода, так как в MSScriptControl передается лишь короткая строка пути к файлу.
Если ответ запрашивается по протоколу HTTP/HTTPS, целесообразно исключить передачу тела ответа в переменные 1С. Запрос выполняется объектом MSXML2.ServerXMLHTTP прямо внутри контекста скрипта:
КодНаJScript =
"function loadAndParseJSON(url) {
| var http = new ActiveXObject('MSXML2.ServerXMLHTTP');
| http.open('GET', url, false);
| http.send();
| var strJSON = http.responseText;
| var parse = (new Function('return(' + strJSON + ');'))();
| return(parse);
|}";
В этом случае весь сетевой обмен и разбор текста происходят в адресном пространстве OLE-компонентов, защищая 1С 7.7 от нехватки памяти при строковых конвертациях.
Если размер ответа превышает несколько мегабайт, встроенный движок MSScriptControl все равно может аварийно завершаться из-за ограничений new Function. В таком случае рекомендуются следующие архитектурные решения:
json_extract или json_tree с прямой выгрузкой результатов в объект ТаблицаЗначений.Scripting.Dictionary или промежуточной конвертацией JSON в XML, разбор которого в 1С 7.7 хорошо отлажен через DOM-модель MSXML2.DOMDocument.