Готовим Soap для Web-сервисов. Рецепты

Обмен - Интеграция с WEB

В статье описаны различные варианты обмена данными с web-сервисами по протоколу Soap, основанные на личном опыте.

Disclaimer: Статей на эту тему написано очень много и, как вы, конечно, догадались, это очередная. Возможно, вы узнаете из неё что-то новое, но ничего сверхсекретного, что нельзя было бы нагуглить самостоятельно, здесь не описано. Только заметки из личного опыта.

Вступление

Рассматривать будем только ситуацию, когда есть сторонний web-сервис и стоит задача наладить обмен данными.

Строение сервиса описывается в файле WSDL (англ. Web Services Description Language)

Файл чаще всего доступен по ссылке, где находится точка входа в сам web-сервис. Я написал «чаще всего», так как бывают исключения. Например, Web-сервис на базе SAP не публикует wsdl и его можно получить только выгрузив из самого приложения.

И так, у нас есть описание web-сервиса, логин, пароль. Давайте подключимся.

// Определяем настройки

URLПространстваИменСервиса = "http://Somesite.ru";
ИмяПользователя = "TestUser";
Пароль = "q1w2e3";
МестоположениеWSDL = "https://Somesite.ru/WebService/Some?wsdl";
ИмяСервиса = "SomeServiceName";
ИмяТочкиПодключения = "SomeService_Port";

// Создаем подключение

SSL = Новый ЗащищенноеСоединениеOpenSSL();
WSОпределение = Новый WSОпределения(МестоположениеWSDL,,,,,SSL);
WSПрокси = Новый WSПрокси(WSОпределение, URLПространстваИменСервиса, ИмяСервиса, ИмяТочкиПодключения,,,SSL);
WSПрокси.Пользователь = ИмяПользователя;
WSПрокси.Пароль = Пароль;

Отлично! Мы подключились к web-сервису! По идее это основа любого варианта обмена, так как позволяет создавать объект структуры данных на основании wsdl, а работать с таким объектом одно удовольствие.

// Создаем объект и наполняем его данными

СвояФабрикаXDTO = WSОпределение.ФабрикаXDTO;

КорневойТип = СвояФабрикаXDTO.Тип(URLПространстваИменСервиса, "SUBMISSION");
КорневойОбъект = СвояФабрикаXDTO.Создать(КорневойТип);

КорневойОбъект.ID = "4356";

КлиентТип = СвояФабрикаXDTO.Тип(URLПространстваИменСервиса, "CUSTOMER");
КлиентОбъект = СвояФабрикаXDTO.Создать(КлиентТип);

КлиентОбъект.CLIENT_ID = "121212";
КлиентОбъект.SEX = "M"; // F - женский, M - мужской
КлиентОбъект.CLIENT_BIRTHDAY = "19900111";

// Автомобили клиента

АвтоТип = СвояФабрикаXDTO.Тип(URLПространстваИменСервиса, "CARS");

АвтоОбъект = СвояФабрикаXDTO.Создать(АвтоТип);
АвтоОбъект.CLASS = "Mercedes";
АвтоОбъект.MODEL = "GLS";

КлиентОбъект.CARS.Добавить(АвтоОбъект);

АвтоОбъект = СвояФабрикаXDTO.Создать(АвтоТип);
АвтоОбъект.CLASS = "Audi";
АвтоОбъект.MODEL = "TT";

КлиентОбъект.CARS.Добавить(АвтоОбъект);

КорневойОбъект.CUSTOMER.Добавить(КлиентОбъект);

Данные успешно заполнены. Теперь нужно их отправить.

В этот самый момент и возникает множество нюансов. Попробуем рассмотреть каждый.

 

Рецепт 1. Отправляем XDTO-объект целиком

Результат = WSПрокси.AddCustomers(КорневойОбъект);

Остается лишь обработать результат, который нам вернул сервис и на этом всё. Согласитесь, что это очень удобно!

Но на практике не всегда бывает так. Например 1с не ладит с префиксацией определенных тэгов внутри xml, когда пространство имен корнеового тэга отличается от пространства дочерних. В таких случаях приходится собирать soap вручную. Так же приходилось сталкиваться с web-сервисами, которые в качестве параметра ждут xml в чистом виде. Маразм, но все же делается это не слишком сложно.

 

Рецепт 2. Отправляем чистый xml в качестве параметра

ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина);
МойXML = Новый ЗаписьXML;
МойXML.УстановитьСтроку(ПараметрыЗаписиXML);
МойXML.ЗаписатьОбъявлениеXML();

СвояФабрикаXDTO.ЗаписатьXML(МойXML, КорневойОбъект);

СтрокаXML = МойXML.Закрыть();

Если УдалитьОписаниеПространстваИмен Тогда
    Попытка
        ПервыйТэгВСтроке = СтрПолучитьСтроку(СтрокаXML,2);
        ИмяКорневогоТэга = КорневойОбъект.Тип().Имя;
        СтрокаXML = СтрЗаменить(СтрокаXML, ПервыйТэгВСтроке, "<"+ИмяКорневогоТэга+">");
    Исключение
        //ОписаниеОшибки()
    КонецПопытки;
КонецЕсли;

Результат = WSПрокси.AddCustomers(СтрокаXML);

Если не удалять пространство имен, которое 1с добавляет по умолчанию, то стало больше всего на 5 строк кода. Чаще всего я заворачиваю преобразование xml в функцию, так как обычно вызываем более одного метода.

 

Рецепт 3. Отправляем через нативный HTTPЗапрос.

СтрокаSOAP = "<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns=""http://Somesite.ru"">
| <soapenv:Header/>
| <soapenv:Body>
|"
+СтрокаXML+
"
| </soapenv:Body>
|</soapenv:Envelope>   "; // 3 пробела в конце обязательно!!!!

// Описываем заголовки HTTP-запроса

Заголовки = Новый Соответствие;
Заголовки.Вставить("Accept-Encoding", "gzip,deflate");
Заголовки.Вставить("Content-Type", "text/xml;charset=UTF-8");
Заголовки.Вставить("SOAPAction", "http://sap.com/xi/WebService/soap1.1");
Заголовки.Вставить("Authorization", "Basic "+ПолучитьBase64ЗаголовокАвторизации(ИмяПользователя, Пароль));
Заголовки.Вставить("Content-Length", Формат(СтрДлина(СтрокаSOAP),"ЧГ=")); // длина сообщения
Заголовки.Вставить("Host", "Somesite.ru:8001");
Заголовки.Вставить("Connection", "Keep-Alive");
Заголовки.Вставить("User-Agent", "Apache-HttpClient/4.1.1 (java 1.5)");

// Подключаемся к сайту.

Соединение = Новый HTTPСоединение("Somesite.ru/WebService/Some",,ИмяПользователя, Пароль,,,SSL, Ложь); // Адрес должен быть без https://

// Получаем текст корневой страницы через POST-запрос.

HTTPЗапрос = Новый HTTPЗапрос("/GetCustomer", Заголовки);
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаSOAP);

Результат = Соединение.ВызватьHTTPМетод("POST", HTTPЗапрос);

В этом варианте нам придется собрать soap вручную. По сути мы просто оборачиваем xml из рецепта 2 в оболочку soap, где в зависимости от требований web-сервиса мы можем менять наш soap как душе угодно.

Далее описываем заголовки согласно документации. Некоторые сервисы спокойно прожуют наш запрос и без заголовков, тут надо смотреть конкретный случай. Если вы не знаете какие заголовки прописывать, то самый простой способ это подглядеть запрос в SoapUI переключившись во вкладку RAW.

Функция получения Base64 строки выглядит так (подсмотрел здесь):

Функция ПолучитьBase64ЗаголовокАвторизации(ИмяПользователя, Пароль)

    КодировкаФайла = КодировкаТекста.UTF8;
    ВременныйФайл = ПолучитьИмяВременногоФайла();
    Запись = Новый ЗаписьТекста(ВременныйФайл, КодировкаФайла);
    Запись.Записать(ИмяПользователя+":"+Пароль);
    Запись.Закрыть();

    ДвДанные = Новый ДвоичныеДанные(ВременныйФайл);
    Результат = Base64Строка(ДвДанные);
    УдалитьФайлы(ВременныйФайл);

    Результат = Сред(Результат,5);

    Возврат Результат;

КонецФункции

В рецепте 3 описано еще несколько важных, но не очевидных моментов, которые возможно справедливы только в моём случае, но я хочу ими поделиться, чтобы вы не наступали на те же грабли, что и я.

  1. Это 3 пробела в конце soap-сообщения. Не знаю почему, но 1с срезала 3 символа в конце soap при отправке данных. Возможно, это глюк конкретной платформы или конкретного web-сервиса или конкретного программиста.
  2. При указании длинны сообщения в заголовке "Content-Length" обязательно указывайте через формат без группировки, а не просто через СтрДлина. Проблема в пробеле который возникает, когда сообщение переваливает за 1 000. На этом многие сыпятся. Попробуйте вбить в гугл запрос "Content-Length", СтрДлина(" и найдете кучу сообщений на форумах, где люди ломают голову о причинах ошибки.

  3. При работе с HTTPСоединение указывайте адрес без указания протоколов «http://» и «https://»
     

Рецепт 4. Отправляем через WinHttpRequest

WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");

WinHttp.Option(2,"UTF-8");
WinHttp.Option(4, 13056); //intSslErrorIgnoreFlag
WinHttp.Option(6, true); //blnEnableRedirects
WinHttp.Option(12, true); //blnEnableHttpsToHttpRedirects

WinHttp.Open("POST", "https://Somesite.ru/WebService/Some/GetCustomer", 0);
WinHttp.SetRequestHeader("Content-type", "text/xml");
WinHttp.SetCredentials(ИмяПользователя, Пароль, 0);

WinHttp.Send(СтрокаSOAP);
WinHttp.WaitForResponse(15);

XMLОтвет = WinHttp.ResponseText();

Здесь по сути тоже самое, что и в предыдущем варианте, но работаем с COMОбъектом. Строку соединения указываем полностью, вместе с протоколом. Особое внимание следует уделить только флагам игнорирования ошибок SSL-сертификатов. Они нужны, если мы работаем по SSL, но без определенного сертификата, так как создать новое защищенное соединение в таком варианте не предоставляется возможным (или я не умею как). В остальном механизм схож с предыдущим.

Так же помимо "WinHttp.WinHttpRequest.5.1" можно использовать "Microsoft.XMLHTTP", "Msxml2.XMLHTTP", "Msxml2.XMLHTTP.3.0", "Msxml2.XMLHTTP.6.0", если вдруг не взлетит на WinHttp. Методы практически такие же, только количество параметров другое. Подозреваю, что один из этих вариантов и зашит внутри объекта 1c HTTPЗапрос.

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

 

Обработка результата

В рецепте 1 мы чаще всего получаем готовый XDTO-объект и работаем с ним как со структурой. Во всех остальных случаях можно преобразовывать xml-ответ в XDTO

Если Результат.КодСостояния = 200 Тогда

ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(Результат.ПолучитьТелоКакСтроку());
ОбъектОтвет = СвояФабрикаXDTO.ПрочитатьXML(ЧтениеXML);
Сообщить(ОбъектОтвет.Body.Response.RESPONSE_ID);
Сообщить(ОбъектОтвет.Body.Response.RESPONSE_TEXT);

КонецЕсли; 

Тут все просто.

 

Вместо заключения

1. Начинайте работу с web-сервисами с программы SoapUI. Она предназначена для таких работ и позволит быстрее понять как работает тот или иной сервис. Для освоения есть статья про SoapUI.

2. Если вы обмениваете с сервисом по незащищенному каналу http и возникает вопрос в том что именно отправляет 1с в своих сообщениях, то можно воспользоваться снифферами трафика такими как Wireshark, Fiddler, и другие. Проблема возникнет только если используете ssl-соединение.

3. Если все же web-сервис общается по https, то ставим на удаленной машине (любой, главное не на своей) сервер Nginx, к которому мы и будем обращаться, а он в свою очередь запакует все в https и перешлет куда нужно (reverse proxy) и в стандартный конфиг добавляем:

server {
    listen 0.0.0.0:8080;
    server_name MyServer;
    location ~ .* {
        proxy_pass https://Somesite.ru:8001;
        proxy_set_header Host $host;
        proxy_set_header Authorization "Basic <base64 ваш пароль:логин>";
        proxy_pass_header Authorization;
    }
}

4. Если вас пугает XDTO, то рекомендую ознакомится с циклом статей злого бобра Андрея XDTO - это просто.

5. Если аутентификация предполагает использование Cookie, то нашлась следующая статья.

 

 

P.S. Если у вас появились вопросы, предложения по улучшению кода, есть собственные рецепты, отличные от описанных, вы нашли ошибки или считаете, что автор "ниправ" и ему "не место в 1с", то пишите комментарии, и мы все обсудим.

 

См. также

Комментарии
Сортировка: Древо
1. unichkin 973 28.12.17 19:03 Сейчас в теме
Через Altova XML spy еще удобно тестить, она и поживее чем Soap UI. Интерфейс такой не дает конечно) Но на практике обычно надо было посылать готовый запрос, а не вбивать его вручную.
2. CSiER 18 29.12.17 16:37 Сейчас в теме
2. Если вы обмениваете с сервисом по незащищенному каналу http и возникает вопрос в том что именно отправляет 1с в своих сообщениях, то можно воспользоваться сниферами трафика такими как Wireshark, Fiddler, и другие. Проблема возникнет только если используете ssl-соединение.
, fiddler - очень удобно, можно работать и с ssl/tls (Tools-Options-HTTPS), а вот Wireshark для этой задачи не так удобен.
3. baton_pk 370 30.12.17 17:20 Сейчас в теме
(0)
Например 1с не ладит с префиксацией определенных тэгов внутри xml, когда пространство имен корнеового тэга отличается от пространства дочерних.


вот на этом месте можно подробнее? И желательно с примерами, если вдруг остались под рукой.
4. 987ww765 105 09.01.18 09:10 Сейчас в теме
(3) Да. Веб-сервис ждет на входе xml следующего вида:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:cus="http://SomeSite.org/customer">
	<soapenv:Header/>
	<soapenv:Body>
		<cus:CustomerCore>
 			<ID>357</ID>
 			<CUSTOMER>
  				<CLIENT_ID>222</CLIENT_ID>
    				<SEX>M</SEX>
  				<CLIENT_TYPE>P</CLIENT_TYPE>
  				<CLIENT_BIRTHDAY>19800101</CLIENT_BIRTHDAY>
				...
 			</CUSTOMER>
		</cus:CustomerCore>
	</soapenv:Body>
</soapenv:Envelope>
Показать


Обратите внимание на префикс cus в версии от SoapUI

И теперь вариант от 1с:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
	<soap:Body>
		<CustomerCore xmlns="http://SomeSite.org/customer" xmlns:xs="http://www.w3.org/2001/XMLSchema"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
			<ID>357</ID>
 			<CUSTOMER>
 				<CLIENT_ID>222</CLIENT_ID>
  				<SEX>M</SEX>
 				<CLIENT_TYPE>P</CLIENT_TYPE>
				<CLIENT_BIRTHDAY>19800101</CLIENT_BIRTHDAY>
				...
 			</CUSTOMER>
		</CustomerCore>
	</soapenv:Body>
</soapenv:Envelope>
Показать


т.е. Пространство имен "http://SomeSite.org/customer" должно распространяться только на элемент CustomerCore, а не на всю ветку.
5. baton_pk 370 09.01.18 10:45 Сейчас в теме
(4) Ну, это вообще косяк принимающей стороны, ибо эти два XML равнозначны по своей сути. И 1С тут нисколько не лукавит, создавая такой запрос.
6. 987ww765 105 09.01.18 11:38 Сейчас в теме
(5) Согласен, но изменить принимающую сторону бывает невозможно и приходится подстраиваться. К тому же SoapUI интерпретировал WSDL ровно так, как того ждал принимающий веб-сервис
7. baton_pk 370 09.01.18 11:53 Сейчас в теме
(6)
и приходится подстраиваться

с этим не поспоришь.

Но лучше обойтись штатными способами:
вместо
СтрокаSOAP = "<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns=""http://Somesite.ru"">
| <soapenv:Header/>
| <soapenv:Body>
|"
+СтрокаXML+
"
| </soapenv:Body>
|</soapenv:Envelope>   "; // 3 пробела в конце обязательно!!!!
Показать


сделать честные ЗаписатьНачалоЭлемента("Envelope"); Потом ЗаписатьСоответствиеПространствИмен("cus", "http://SomeSite.org/customer");

и уже потом в эту же запись XML записать фабрикой необходимый объект. Потом закрыть запись и добавить три пробела, если уж принимающая сторона настолько упорота.

Всё же, пилить XML текстом - неблагодарное дело.
VasilVtoroy; +1 Ответить
8. 987ww765 105 09.01.18 12:18 Сейчас в теме
(7) Но это же тоже самое. Строку xml я формирую не сам, а получаю из фабрики. Опять же, не претендую на правду в последней инстанции.
9. baton_pk 370 09.01.18 12:21 Сейчас в теме
(8) я про разделы Envelope и Body. Если их записать штатными средствами платформы и в них же туда прописать соответствие пространств имён с нужным префиксом, то фабрика при записи объекта уже не будет совать xmlns, так как он уже будет не нужен.
10. 987ww765 105 09.01.18 15:06 Сейчас в теме
(9) Видимо я не понял суть решения. То есть создаем объект ЗаписьXML, прописываем Envelope, Body. Отлично. Как потом дружим их с фабрикой?
11. baton_pk 370 09.01.18 15:45 Сейчас в теме
(10) точно так же:

СвояФабрикаXDTO.ЗаписатьXML(МойXML, КорневойОбъект);


где перед этим кодом запись начал элементов Envelope и Body с указанием пространств имён, а после этого конца, соответственно, закрытие элементов Body и Envelope.
20. nikolayvg 18 13.07.18 10:41 Сейчас в теме
(4)Здравствуйте. Вопрос не по теме, но относительно вашего комментария.
Я создаю WSПрокси, заполняю параметры и вызываю метод GetReferenceData.

СервисЭП = WSСсылки.cse.СоздатьWSПрокси("http://www.cargo3.ru", "WebService", "WebServiceSoap");
	
	
	ТипWSПараметра1 = СервисЭП.ФабрикаXDTO.Пакеты.Получить("http://www.cargo3.ru").Получить("Element");//GetReferenceData");
	WSПараметр1 = СервисЭП.ФабрикаXDTO.Создать(ТипWSПараметра1);
	WSПараметр1.Key	= "Reference";
	WSПараметр1.ValueType	= "string";
	WSПараметр1.Value	= "Currencies";
	
	
	ТипWSПараметра = СервисЭП.ФабрикаXDTO.Пакеты.Получить("http://www.cargo3.ru").Получить("Element");//GetReferenceData");
	WSПараметр	   = СервисЭП.ФабрикаXDTO.Создать(ТипWSПараметра);
	WSПараметр.Key	= "parameters";
	WSПараметр.List.Добавить(WSПараметр1);
	
	Данные = СервисЭП.GetReferenceData(Логин, Пароль, WSПараметр);
Показать


Каким образом я могу сначала посмотреть xml запрос, который отправляется? Просто возникает ошибка, а отладить не получается.
21. 987ww765 105 17.07.18 10:00 Сейчас в теме
(20) Можно преобразовать обратно из фабрики в XML

	
	МойXML = Новый ЗаписьXML;
	МойXML.УстановитьСтроку(Новый ПараметрыЗаписиXML("UTF-8", "1.0", Истина));
	МойXML.ЗаписатьОбъявлениеXML();
	
	СервисЭП.ФабрикаXDTO.ЗаписатьXML(МойXML, WSПараметр); 
	
	СтрокаXML = МойXML.Закрыть();
Показать


Но лучше всего воспользоваться сниферами типа Fiddler, Wireshark и т.д. Такой метод будет более точным.
nikolayvg; +1 Ответить
22. nikolayvg 18 18.07.18 06:10 Сейчас в теме
(21) Спасибо. Fiddler помог. Нашел единственное отличие. Почему-то 1С не формирует тег <soap:Header/>.
Должно быть
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header/>
<soap:Body>
<m:GetReferenceData xmlns:m="http://www.cargo3.ru">
а у меня
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<m:GetReferenceData xmlns:m="http://www.cargo3.ru">
где искать причины?
23. 987ww765 105 20.07.18 15:00 Сейчас в теме
(22) Это заголовки. Я не знаю как насильно прописать заголовок в XML при работе с фабрикой. Вообще по идее он никак не должен влиять на поведение системы. Уверены, что наличие <soap:Header/> изменит ситуацию?
12. myr4ik07 114 27.01.18 22:01 Сейчас в теме
Есть веб сервис который на вход принимает ID, KEY (string)

Смотрю через SoapUI структура

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:api2="http:/name/Api20" xmlns:int="http://name/integration20">
<soap:Header/>
<soap:Body>
<api2:AllCatalog>
<api2:AllCatalogRequest>
<int:Auth>
<int:ID></int:ID>
<int:KEY></int:KEY>
</int:Auth>
</api2:AllCatalogRequest>
</api2:AllCatalog>
</soap:Body>
</soap:Envelope>
Показать


как данную структуру описать из 1С?
13. 987ww765 105 30.01.18 08:10 Сейчас в теме
(12) Сейчас 1с неправильно формирует? Раз через SoapUI работаете, то описание веб сервиса (wsdl) у вас есть. Попробуйте так как описано в статье (Вступление и рецепт 1). У вас соответственно будет вот так:

// Создаем объект и наполняем его данными

СвояФабрикаXDTO = WSОпределение.ФабрикаXDTO;

КорневойТип = СвояФабрикаXDTO.Тип(URLПространстваИменСервиса, "AllCatalog");
КорневойОбъект = СвояФабрикаXDTO.Создать(КорневойТип);

ЗапросСправочниковТип = СвояФабрикаXDTO.Тип(URLПространстваИменСервиса, "AllCatalogRequest");
ЗапросСправочниковОбъект = СвояФабрикаXDTO.Создать(ЗапросСправочниковТип );

АвторизацияТип = СвояФабрикаXDTO.Тип(URLПространстваИменСервиса, "Auth");
АвторизацияОбъект = СвояФабрикаXDTO.Создать(АвторизацияТип );

АвторизацияОбъект.ID = "121212";
АвторизацияОбъект.KEY= "**********";

ЗапросСправочниковОбъект.Auth = АвторизацияОбъект;
КорневойОбъект.AllCatalogRequest = ЗапросСправочниковОбъект;

Показать
myr4ik07; +1 Ответить
14. myr4ik07 114 30.01.18 08:54 Сейчас в теме
15. VasilVtoroy 30.01.18 18:52 Сейчас в теме
1) Content-Length устанавливать не надо.
Платформа сама его правильно посчитает (в отличие от приведенного кода)


2) Fiddler тоже позволяет перехватывать защищенные http-соединения

3) Заголовок Host тоже не надо устанавливать

4) Basic-авторизацию можно делать не вручную, а задав в HTTPСоединения свойства логин и пароль.
Таким образом вы и Windows аутентификацию можете делать.

5) Accept-Encoding устанавливать просто нельзя, платформа не поддерживает сжатие HTTP!
16. 987ww765 105 31.01.18 07:59 Сейчас в теме
(15) Заголовки я не сам придумал. Это было одним из требованием принимающей стороны. По поводу Fiddler`а согласен, но я поздно узнал, что он умеет перехватывать https.
17. VasilVtoroy 31.01.18 15:11 Сейчас в теме
(16) Я же не говорю, что он не нужны.
Но пункты (1) и (3) платформа формирует сама, и более правильно

По пункту (4) - тоже самое можно сделать проще

По пункту (5) - такого требования точно быть не могло. Если бы на другой стороне был сервер с поддержкой сжатия, то вы бы получили чушь вместо ответа
18. almas 193 16.03.18 09:50 Сейчас в теме
Спасибо, за информацию. Статья очень помогла для настройки подключения к SilverDat.
19. 987ww765 105 21.03.18 09:54 Сейчас в теме
(18) Это здорово. Были какие-то особенности при настройке обмена?
Оставьте свое сообщение