Как передать JSON по HTTPS из 1С 7.7 с помощью WinHttpRequest и решить ошибку 415 Unsupported Media Type?

Программист 1С v7.7
← На главную

Передача данных в формате JSON по протоколу HTTPS из устаревшей платформы 1С 7.7 является частой задачей при интеграции с современными веб-сервисами. Однако, на этом пути можно столкнуться с различными сложностями, одной из которых является ошибка 415 Unsupported Media Type. В этом руководстве мы подробно разберем, как осуществить такую передачу, используя объекты WinHttp.WinHttpRequest.5.1 или Msxml2.ServerXMLHTTP, и выясним, как правильно преодолеть упомянутую ошибку.

Мы рассмотрим несколько подходов к решению задачи, проанализируем распространенные ошибки и предоставим готовые примеры кода для внедрения в ваши конфигурации 1С 7.7. Давайте приступим к детальному изучению.

Начальные попытки и анализ ошибки "Объект не поддерживает это свойство или метод"

Изначально при попытке отправить JSON из файла с использованием WinHttp.WinHttpRequest.5.1 и ADODB.Stream через MSScriptControl.ScriptControl, пользователи часто сталкиваются с ошибкой "Объект не поддерживает это свойство или метод". Давайте проанализируем первоначальный код и исправим эту проблему.


WinHttp  = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
WinHttp.Open(СокрЛП("POST"), СокрЛП(Адрес),0);
WinHttp.SetCredentials(Логин,Пароль,0);
WinHttp.SetRequestHeader("Authorization"," Basic " + глКодироватьСтрокуВ_Base64(Логин+":"+Пароль));

СтримЧтение = СоздатьОбъект("ADODB.Stream");
СтримЧтение.Type    = 1;
СтримЧтение.Mode    = 3;
//СтримЧтение.Charset = "UTF-8"; // Эта строка вызывала ошибку "Операция не допускается в данном контексте"
СтримЧтение.Open();

Скрипт = СоздатьОбъект("MSScriptControl.ScriptControl");
Скрипт.Language     = "VBScript"; 
Скрипт.Timeout        = -1;
// Ошибка здесь: Скрипт.AddObject("StreamRead",WinHttp); - StreamRead должен быть ADODB.Stream
Скрипт.AddObject("winhttp",WinHttp);
СтримЧтение.LoadFromFile("d:\ref.txt");

Если СтримЧтение.Type=1 Тогда
    Скрипт.Eval("winhttp.send(StreamRead.Read())");  // Объект WinHttp не имеет метода Read(), ReadText()
Иначе
    Скрипт.Eval("winhttp.send(StreamRead.ReadText())");
КонецЕсли;

Основная причина ошибки "Объект не поддерживает это свойство или метод" заключается в неправильной передаче объекта в MSScriptControl.ScriptControl. В строке Скрипт.AddObject("StreamRead",WinHttp); в качестве объекта StreamRead ошибочно передавался сам WinHttp, тогда как должен был быть передан объект СтримЧтение (ADODB.Stream), который и обладает методами Read() и ReadText(). Также, если StreamRead будет ADODB.Stream, то метод winhttp.send() не поддерживает передачу данных напрямую из ADODB.Stream методом Read() в VBScript. Вместо этого, нужно сначала прочитать данные из потока в переменную, а затем передать эту переменную в WinHttp.Send().

Исправленный код, учитывающий правильную привязку объекта ADODB.Stream и прямое чтение, выглядит так:


WinHttp  = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
WinHttp.Open(СокрЛП("POST"), СокрЛП(Адрес),0);
WinHttp.SetCredentials(Логин,Пароль,0);
WinHttp.SetRequestHeader("Authorization"," Basic " + глКодироватьСтрокуВ_Base64(Логин+":"+Пароль));

СтримЧтение = СоздатьОбъект("ADODB.Stream");
СтримЧтение.Type    = 1; // 1 = adTypeBinary
СтримЧтение.Mode    = 3; // 3 = adModeReadWrite
//СтримЧтение.Charset = "UTF-8"; // Эта строка может вызвать ошибку, если поток уже открыт
СтримЧтение.Open();
СтримЧтение.LoadFromFile("d:\ref.txt");

// Читаем данные из потока в переменную 1С
Если СтримЧтение.Type = 1 Тогда // Бинарный поток
    ДанныеДляОтправки = СтримЧтение.Read(-1); // Читаем все данные
Иначе // Текстовый поток
    ДанныеДляОтправки = СтримЧтение.ReadText(-1); // Читаем весь текст
КонецЕсли;
СтримЧтение.Close();

// Теперь отправляем данные напрямую
WinHttp.Send(ДанныеДляОтправки);

Однако, даже после исправления этой проблемы, мы сталкиваемся с новой, более фундаментальной ошибкой: Status: 415 StatusText: Unsupported Media Type.

Разбираем ошибку "415 Unsupported Media Type"

Ошибка 415 Unsupported Media Type означает, что сервер отказывается принимать ваш запрос, потому что формат содержимого, который вы отправляете, не поддерживается или не ожидается сервером для данного запроса. Проблема кроется в заголовке Content-Type, который отправляется вместе с запросом. Если вы отправляете JSON, сервер ожидает, что в заголовках запроса будет явно указано, что тело запроса содержит данные в формате JSON.

При использовании WinHttpRequest или XMLHttpRequest по умолчанию этот заголовок может не устанавливаться или устанавливаться в другое значение (например, application/x-www-form-urlencoded), что и приводит к ошибке 415.

Давайте посмотрим на шаги по устранению этой ошибки.

Решение: Установка заголовка Content-Type

Ключевым моментом для успешной передачи JSON является явное указание заголовка Content-Type со значением application/json. Это информирует сервер о том, какой тип данных содержится в теле вашего запроса.

Рассмотрим подробнее, как это сделать с объектами WinHttp.WinHttpRequest.5.1 и Msxml2.ServerXMLHTTP.

Решение для WinHttp.WinHttpRequest.5.1

Если вы используете WinHttp.WinHttpRequest.5.1, добавление заголовка выполняется одной строкой перед отправкой запроса:


WinHttp  = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
WinHttp.Open(СокрЛП("POST"), СокрЛП(Адрес),0);
WinHttp.SetCredentials(Логин,Пароль,0);
WinHttp.SetRequestHeader("Authorization"," Basic " + глКодироватьСтрокуВ_Base64(Логин+":"+Пароль));
// *** ВАЖНОЕ ИСПРАВЛЕНИЕ: устанавливаем Content-Type ***
WinHttp.SetRequestHeader("content-type","application/json");

// Подготавливаем JSON данные из файла
Т = СоздатьОбъект("Текст");
Т.Открыть("d:\ref.txt");
Отправить = "";
Для инд = 1 по Т.КоличествоСтрок() Цикл
    Отправить = Отправить + Т.ПолучитьСтроку(инд);
КонецЦикла;    
Т.Закрыть();

WinHttp.Send(Отправить); 

Обратите внимание на строку WinHttp.SetRequestHeader("content-type","application/json"); – именно она решает проблему 415 ошибки.

Решение для Msxml2.ServerXMLHTTP (или аналогичных XMLHttpRequest)

Для объектов типа Msxml2.ServerXMLHTTP (часто используемых через общую функцию СоздатьXMLHttpRequest) подход аналогичен. Вам также необходимо установить заголовок Content-Type. Рассмотрим полный пример, включая вспомогательные функции, которые могут быть полезны в 1С 7.7.

Прежде всего, нам потребуются вспомогательные функции для создания объекта XMLHttpRequest с учетом различных версий и для генерации GUID.


// *** Функция для создания объекта XMLHttpRequest ***
Функция СоздатьXMLHttpRequest(URL,Метод = "GET")
    
    Попытка
        XMLHttpRequest = СоздатьОбъект("Msxml2.ServerXMLHTTP");
    Исключение
        Попытка
            XMLHttpRequest = СоздатьОбъект("Msxml2.XMLHTTP.3.0");
        Исключение
            Попытка
                XMLHttpRequest = СоздатьОбъект("Msxml2.XMLHTTP");
            Исключение
                Попытка
                    XMLHttpRequest = СоздатьОбъект("Microsoft.XMLHTTP");
                Исключение
                    Сообщить("Невозможно создать XMLHttpRequest.                                                                         
                    |" + ОписаниеОшибки(), "!");
                КонецПопытки;
            КонецПопытки;
        КонецПопытки;
    КонецПопытки;
    
    XMLHttpRequest.open(Метод, URL, 0);
    
    Возврат XMLHttpRequest;
    
КонецФункции

// *** Функция для создания GUID ***
Функция СоздатьGUID()
    TypeLib = CreateObject("Scriptlet.TypeLib");
    NewGUID = TypeLib.Guid();
    TypeLib = "";
    Возврат NewGUID;
КонецФункции

Теперь, используя эти функции, мы можем реализовать отправку JSON с корректным заголовком:


// Пример использования XMLHttpRequest
// ... (предполагаем, что Логин, Пароль, Адрес определены) ...

XMLHttpRequest = СоздатьXMLHttpRequest(Адрес,"POST");
XMLHttpRequest.SetRequestHeader("Authorization"," Basic " + глКодироватьСтрокуВ_Base64(Логин+":"+Пароль));
// *** ВАЖНОЕ ИСПРАВЛЕНИЕ: устанавливаем Content-Type ***
XMLHttpRequest.SetRequestHeader("content-type","application/json");

// Дополнительные заголовки, если требуются API
// XMLHttpRequest.setRequestHeader("Accept", "application/json"); 
// XMLHttpRequest.setRequestHeader("X-Api-Key", Токен);
// XMLHttpRequest.setRequestHeader("X-Origin-Request-Id", Строка(СоздатьGUID()));
// XMLHttpRequest.setRequestHeader("X-Timestamp", Строка(ТекущаяДата()) + "T" + Строка(ТекущееВремя()) + ".000Z");

// Подготавливаем JSON данные из файла
Т = СоздатьОбъект("Текст");
Т.Открыть("d:\ref.txt");
Отправить = "";
Для инд = 1 по Т.КоличествоСтрок() Цикл
    Отправить = Отправить + Т.ПолучитьСтроку(инд);
КонецЦикла;    
Т.Закрыть();

XMLHttpRequest.send(Отправить); 

// Обработка ответа
ОтветОтСервера = СокрЛП(XMLHttpRequest.responseText);
Сообщить("Status: " + XMLHttpRequest.status);
Сообщить("StatusText: " + XMLHttpRequest.statusText);
Сообщить("ResponseText: " + ОтветОтСервера);

Как мы видим, принцип решения одинаков: добавление строки SetRequestHeader("content-type","application/json");.

Особенности кодировки JSON в 1С 7.7

JSON по своей природе является текстовым форматом и обычно использует кодировку UTF-8. В 1С 7.7 работа с UTF-8 может быть неочевидной, поскольку платформа изначально работает с системной кодировкой (как правило, Windows-1251 для русских версий).

При чтении JSON из файла (как в примере d:\ref.txt) важно убедиться, что файл сохранен в кодировке UTF-8. Если файл сохранен в другой кодировке, а JSON содержит нелатинские символы (например, кириллицу), они могут быть некорректно прочитаны 1С, что приведет к битому JSON на стороне сервера. Объект ADODB.Stream может помочь с перекодировкой, но его использование требует внимательности.

Если строка JSON формируется программно в 1С 7.7 (путем конкатенации), то символы обычно будут в системной кодировке. В большинстве случаев WinHttpRequest сам осуществляет необходимую перекодировку при отправке, но иногда может потребоваться использовать внешние компоненты (например, 1С++) для явной конвертации строки в UTF-8 перед отправкой, особенно если сервер очень строго относится к кодировке. В заголовке Content-Type иногда можно указать кодировку: application/json; charset=utf-8, но это может вызвать проблемы с некоторыми серверами, поэтому рекомендуется сначала попробовать без явного указания charset.

Различия между WinHttpRequest и XMLHttpRequest

Для выполнения HTTP-запросов в 1С 7.7 (и не только) часто используют два основных типа COM-объектов:

  1. WinHttp.WinHttpRequest.5.1: Этот объект основан на библиотеке WinHTTP, которая является частью операционной системы Windows и оптимизирована для серверных сценариев и автоматизированных задач. Он независим от настроек Internet Explorer и обычно считается более надежным и производительным для работы из сервисов или скриптов. WinHttpRequest хорошо поддерживает HTTPS, прокси-серверы и различные методы аутентификации.
  2. Msxml2.ServerXMLHTTP (и другие версии Msxml2.XMLHTTP): Эти объекты основаны на библиотеке MSXML, которая использует WinINet. WinINet тесно связана с Internet Explorer и может зависеть от его настроек (например, настройки прокси, сертификаты). Msxml2.ServerXMLHTTP является "серверной" версией XMLHTTP, которая также построена на базе WinHTTP, что делает ее более предпочтительной для серверного использования по сравнению с обычным Msxml2.XMLHTTP. Тем не менее, WinHttpRequest часто предпочитают за простоту и стабильность.

В целом, оба объекта способны выполнять поставленную задачу. Выбор часто зависит от конкретных условий и предпочтений разработчика. В наших примерах мы показали, как решить проблему 415 ошибки для обоих подходов.

Безопасность при передаче данных по HTTPS

При использовании HTTPS вы обеспечиваете шифрование передаваемых данных, что защищает их от перехвата. Однако важно помнить о следующих аспектах:

  1. Базовая аутентификация (Basic Authentication): Использование заголовка Authorization: Basic ... предполагает кодирование логина и пароля в Base64. Это не является шифрованием, а лишь кодированием. Именно HTTPS обеспечивает шифрование этого закодированного значения при передаче по сети. Поэтому, никогда не используйте Basic Authentication по HTTP (без SSL/TLS), так как ваши учетные данные будут легко доступны для перехвата.
  2. SSL/TLS сертификаты: Убедитесь, что сервер, к которому вы подключаетесь, использует действительный и доверенный SSL/TLS сертификат. В 1С 7.7 и используемых COM-объектах по умолчанию проверяются стандартные хранилища доверенных сертификатов Windows. Если вы работаете с самоподписанными сертификатами или сертификатами из корпоративных ЦС, может потребоваться дополнительная настройка доверия на клиентской машине.

Формирование JSON в 1С 7.7

В отличие от более новых версий 1С:Предприятие, в 1С 7.7 нет встроенных функций для автоматического формирования и парсинга JSON. Формирование JSON-строки чаще всего осуществляется путем ручной конкатенации строк, что может быть громоздким и подверженным ошибкам, особенно для сложных структур. Рассмотрим пример формирования JSON-строки вручную, как это было показано в обсуждении:


// Пример формирования JSON-строки вручную
Сумма = 1000;
БалловСписать = 10;
КодКлиента = "999593";
ДокНомер = "00005";
ПродавецID = "UDS123";

Отправить = "{" + Симв(34) + "scores" + Симв(34) + ":" + Симв(34) +  СокрЛП(БалловСписать)+ Симв(34) +","
+ Симв(34) +"total"+ Симв(34) + ":" +Симв(34)+ Строка(Сумма) + Симв(34) +","
+ Симв(34) + "cash"+ Симв(34) + ":" + Симв(34)+ Строка(Сумма-БалловСписать)+ Симв(34) +",";
Если СтрДлина(СокрЛП(КодКлиента)) = 6 Тогда
    Отправить = Отправить + Симв(34) + "code"+ Симв(34) + ":"+ Симв(34) + СокрЛП(КодКлиента)+ Симв(34) +","; 
Иначе
    Отправить = Отправить + Симв(34) + "phone"+ Симв(34) + ":%2B7"+ Симв(34) + СокрЛП(КодКлиента)+ Симв(34) +","; 
КонецЕсли; 
Отправить = Отправить + Симв(34) + "invoiceNumber" +  Симв(34) + ":" + Симв(34) + СокрЛП(Прав(ДокНомер,5)) +  Симв(34)+ ","
+Симв(34) + "cashierExternalId"  + Симв(34) + ":" + Симв(34) + СокрЛП(ПродавецID) +  Симв(34) +"}";

// Отправить теперь содержит строку JSON
Сообщить(Отправить);

Для сложных JSON-структур ручное формирование может стать неуправляемым. В таких случаях программисты 1С 7.7 часто прибегают к использованию внешних компонент (например, 1С++) или JavaScript/VBScript, исполняемых через MSScriptControl.ScriptControl, для создания и сериализации JSON-объектов. Эти инструменты позволяют работать с JSON более удобно, создавая объекты, а затем преобразуя их в строку JSON.

Заключение

Мы выяснили, что основной причиной ошибки 415 Unsupported Media Type при отправке JSON по HTTPS из 1С 7.7 является отсутствие или некорректное значение заголовка Content-Type. Решение заключается в явной установке этого заголовка в значение application/json перед отправкой запроса. Мы рассмотрели примеры кода для двух популярных COM-объектов – WinHttp.WinHttpRequest.5.1 и Msxml2.ServerXMLHTTP, а также обсудили связанные аспекты, такие как кодировка, безопасность и формирование JSON.

Следуя этим рекомендациям и используя предоставленные примеры кода, вы сможете успешно реализовать передачу JSON-данных из 1С 7.7, интегрируя вашу систему с современными веб-сервисами.

← На главную