Имя: Пароль:
1C
1С v8
Помогите с запросом к api Mango office WinHttp.WinHttpRequest
,
0 ILNIK19
 
30.08.17
17:17
Добрый день.
Уже несколько дней бьюсь над проблемой.
Нужно сделать запрос к api АТС Манго офис.
Надо получить статистику по звонкам, для этого сделать первый запрос с требуемыми параметрами статистики, потом api возвращает ключ, и ты делаешь второй запрос с этим ключом, для получения данных.
В принципе он срабатывает, но есть проблема.

Когда в ключе есть символ "+", то при отправке он превращается в пробел.
Т.е. я в отладке вижу, что отправляю ключ и в нем есть знак "+", а тех поддержка видит ,что в отсылаемом им ключе вместо "+" стоит пробел.
Если ключ не содержит "Плюсов", то все срабатывает как надо, без ошибок.

Т.е. запрос статистики срабатывает через раз ,если повезет и не будет в ключе плюса, то ок, иначе ошибка
401. {"name":"Unauthorized","message":"You are requesting with an invalid credential.","code":0,"status":401}

В чем может быть дело?

Пример запроса с плюсом:

vpbx_api_key=УнКод&sign=sign&json={
"key": "dMSffJ+si2a/44IqQrN22ugkjW1IuSBXEf76rmmqSFyY5kGYr/pu/4fOJu+2zK7IJTqcdyiSgybRpXOeDJZnkg=="
}

Текст запроса данных:

Ключ = ОтправитьЗапросНаСтатитистикуИПолучитьКлюч();

УнКод = "МойКод";
УнКлюч = "МойКлюч";
        
data = Новый Структура;
data.Вставить("key", Ключ);    

ЗаписьJSON = Новый ЗаписьJSON();
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, data);
СтрокаJson = ЗаписьJSON.Закрыть();
    
    Хеширование = Новый ХешированиеДанных(ХешФункция.SHA256);
    Хеширование.Добавить(УнКод); // vpbx_api_key
    Хеширование.Добавить(СтрокаJson); // json
    Хеширование.Добавить(УнКлюч);// vpbx_api_salt
    sign = Хеширование.ХешСумма;
    sign = СтрЗаменить(НРЕГ(sign), " ", "");
    
    postdata = Новый Соответствие;
    postdata.Вставить("vpbx_api_key", УнКод);
    postdata.Вставить("sign", sign);
    postdata.Вставить("json", СтрокаJson);
    
    post = "vpbx_api_key=" + postdata.Получить("vpbx_api_key")  + "&" +
    "sign=" + postdata.Получить("sign")                         + "&" +
    "json=" + postdata.Получить("json");
    
    Сообщить(post);    
    
    WinHttp = Неопределено;
    Попытка                       
        WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
        WinHttp.Option(2, "CESU-8");
        WinHttp.Open("POST", "https://app.mango-office.ru/vpbx/stats/result",0);
                //Пробовал еще такое добавлять. Также пробовал ставить кодировку utf-8
        //WinHttp.SetRequestHeader("Accept-Language", "en");
        //WinHttp.SetRequestHeader("Accept-Charset","utf-8");
        //WinHttp.setRequestHeader("Content-Language", "en");
        //WinHttp.setRequestHeader("Content-Charset", "utf-8");
        WinHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=CESU-8");
        WinHttp.Send(post);
        ТекстОтвета = WinHttp.ResponseText();         
        ТекстПредупреждения = ТекстОтвета;                
    Исключение
        ТекстПредупреждения = ОписаниеОшибки();
    КонецПопытки;
1 ILNIK19
 
30.08.17
17:18
Вот пример на PHP из их руководства

$api_key = '<YOUR_API_KEY>';
$api_salt = '<YOUR_API_SALT>';
$url = 'https://app.mango-office.ru/vpbx/stats/result';
$data = array(
"key" => "<REQUEST_KEY>"
);
// json = {"key":"<REQUEST_KEY>"}
$json = json_encode($data);
// sign = 515069b8c079df62f408e36dd7933912b8e86d833c5927ee77eb4b68d766c4f5
$sign = hash('sha256', $api_key . $json . $api_salt);
/*
array (
'vpbx_api_key' => '<YOUR_API_KEY>',
'sign' => '515069b8c079df62f408e36dd7933912b8e86d833c5927ee77eb4b68d766c4f5',
'json' => '{"key":"<REQUEST_KEY>"}',
)
*/
$postdata = array(
'vpbx_api_key' => $api_key,
'sign' => $sign,
'json' => $json
);
// post = vpbx_api_key=%3CYOUR_API_KEY%3E&sign=515069b8c079df62f408e36dd7933912b8e86d833c5927ee77eb4b68d766c4f5&json=%7B%22key%22%3A%22%3CREQUEST_KEY%3E%22%7D
$post = http_build_query($postdata);
/************ Отправка с использованием file_get_contents ************/
$opts = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => $post
)
);
$context = stream_context_create($opts);
$response = file_get_contents($url, false, $context);
/************ Отправка с использованием cUrl ************/
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
$response = curl_exec($ch);
curl_close($ch);
2 Филиал-msk
 
30.08.17
17:39
(1) > 'header' => 'Content-type: application/x-www-form-urlencoded',

Как думаешь, что это означает?
3 ILNIK19
 
30.08.17
19:17
(2) Это формат для кодирования пар ключ-значение с возможностью дублирования ключей. Каждая пара ключ-значение отделяется символом &, ключ отделён от значения символом = . В ключах и значениях пробелы заменяются на знак +, и затем, используя URL-кодирование, заменяются все не буквенно-цифровые символы.
4 ILNIK19
 
30.08.17
19:20
(2) Хэш выходит в виде хх хх хх хх... и тд. Я удаляю пробелы. Может из-за этого?
Но вряд ли api примет хэш с пробелами
5 Филиал-msk
 
30.08.17
19:31
(4) > ...и затем, используя URL-кодирование, заменяются все не буквенно-цифровые символы

И?
6 ILNIK19
 
30.08.17
19:47
(5) вы можете сказать, что нужно конкретно сделать? Или будем играть в загадки?
7 Филиал-msk
 
30.08.17
20:20
(6) Мне надо чтобы ты заебался и задумался. А тебе надо готового кода и поиграться. Ок.
При отправке http запроса необходимо согласовать с сервером кодировку данных. В силу того, что http поточный протокол, информация о методе кодирования данных отправляется раньше, в заголовках. Поэтому, для нормальной работы необходимо передать тело запроса в соответствующем виде.

Твоя очередь. Ебись (:
8 Филиал-msk
 
30.08.17
23:00
А сейчас выскочит Serginio1 и даст ссылку на Ъ (:
9 Lexey_
 
30.08.17
23:30
(0)а зачем WinHttpRequest? Есть же HTTPЗапрос
10 Lexey_
 
30.08.17
23:37
+(9) да ещё и стаж 10 лет, че за фетиш такой на WinHttpRequestы?
11 Лодырь
 
31.08.17
05:01
(10) Ну вот он и вспомнил времена старинные, когда HTTPЗапроса не было, а приходилось использовать WinHTTP.
12 ILNIK19
 
31.08.17
07:31
(10) (11) я уже с этой задачей и так время от времени занимаюсь пару недель.
httpЗапрос пробовал разными вприантами. Манго возвращает ошибку аутентификации, хотя у них полность открытый доступ к api и никакой лог н и пароль не нужен. Пустой прокси прописывал. Защищенное соединение тоже пробовал.
ВинРеквест работает, осталось только допилить чуток.
Я правильно понимаю, что ошибка не в ключе, а в заголовке? Надосюла копать?
13 Филиал-msk
 
31.08.17
07:39
(10) Меня вот больше интересует биологическая особенность, которая проявляется у всех со временем стажа, после обвешивания себя сертификатами и прочими регалиями. У людей напрочь отрубается способность читать написанное, даже то, что они написали своими руками. Пост (2) тому явный пример.
14 Филиал-msk
 
31.08.17
07:40
Пост (3), промахнулся.
15 Филиал-msk
 
31.08.17
07:44
Вот так вот пару недель на одной задаче, пару на другой - вот и 10 лет стажа. Удобно!
16 ILNIK19
 
31.08.17
08:59
(15) Предлагаю не захламлять тему бесполезными постами. Никому не интересны домыслы разных "спецов", считающих себя самыми умными. Если нечего сказать по делу, то, пожалуйста, не умничайте и не отвлекайте других.
Занимаюсь этой темой пару недель, потому что есть основная работа с тремя активными проектами. А данная задача является факультативом в свободное время
17 ILNIK19
 
31.08.17
09:03
(15) Все знать невозможно. 1сники со стажем могут заменить и бухгалтера и кадровика и узких специалистов в разных предметных областях вместе взятых. Всегда будет что-то новое. Есть задача, есть разные пути решения. И ни одно решение не является истиной. Так что ваши потуги под...ать других людей не красят вас. Всегда найдется область в которой вы будете профаном, а другой человек обставит вас в два счета
18 Lexey_
 
31.08.17
09:23
Функция ВыполнитьЗапрос(АдресРесурса, ПараметрыЗапроса)

    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку(Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет);
    ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапроса);
    СтрокаJSON = ЗаписьJSON.Закрыть();
        
    ХД = Новый ХешированиеДанных(ХешФункция.SHA256);
    ХД.Добавить(ApiKey);
    ХД.Добавить(СтрокаJSON);
    ХД.Добавить(ApiSalt);
    Sign = НРег(СтрЗаменить(ХД.ХешСумма, " ", ""));
    
    HTTPСоединение = Новый HTTPСоединение("app.mango-office.ru", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL());
    
    СтрокаЗапроса = СтрШаблон("vpbx_api_key=%1&sign=%2&json=%3", ApiKey, Sign, СтрокаJSON);
    
    ЗаголовкиHTTP = Новый Соответствие;
    ЗаголовкиHTTP.Вставить("Content-type", "application/x-www-form-urlencoded");
    HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, ЗаголовкиHTTP);
    HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаЗапроса);
    Возврат HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
        
КонецФункции


пример вызова:

ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("key", key);

HTTPОтвет = ВыполнитьЗапрос("vpbx/stats/result", ПараметрыЗапроса);
19 Филиал-msk
 
31.08.17
09:33
(18) Не взлетит. Будет ровно та же самая ошибка.
20 Lexey_
 
31.08.17
09:36
(19) уже несколько месяцев исправно летает
21 Филиал-msk
 
31.08.17
09:39
(17) Я, кажется, понял. При подготовке к обвешиванию сертификатами применяется подход, который намертво вшивается в подкорку - зазубрить шаблоны примеров и попытаться применить их, надеясь на удачу.
В последующем, ровно такой же подход применяется специалистом и в разработке - программирование методом тыка наудачу. Чтобы отстали. Скопировать кусок руководства из интернета, ответить им на сарказм... Чтоб прочувствовали, а то ишь!
Думать и читать скопированное совсем не обязательно. И даже вредно для сертифицированных специалистов.
22 Филиал-msk
 
31.08.17
09:41
(20) добавь в тело запроса с такими заголовками, например, русские буквы.
23 Филиал-msk
 
31.08.17
09:47
(22) хотя можно и показательнее. Добавь в передаваемые данные, например, знак равенства.
24 ILNIK19
 
31.08.17
09:58
(18) Не работает. Даже когда плюса нет
25 ILNIK19
 
31.08.17
10:02
{"name":"Unauthorized","message":"You are requesting with an invalid credential.","code":0,"status":401}
26 Lexey_
 
31.08.17
10:20
(23) да, забыл КодироватьСтроку(СтрокаJSON, СпособКодированияСтроки.КодировкаURL)
27 Lexey_
 
31.08.17
10:21
СтрокаЗапроса = СтрШаблон("vpbx_api_key=%1&sign=%2&json=%3", ApiKey, Sign, КодироватьСтроку(СтрокаJSON, СпособКодированияСтроки.КодировкаURL));
28 ILNIK19
 
31.08.17
10:35
(27) vpbx_api_key=Мойkey&sign=Мойsign&json=%7B%0D%0A%22key%22%3A%20%22T9OyJplIzuuUwYXo7SHmNYnTHG3EPAdo0q4TH0yomf0uhXTCWvUhLWTaNFJ7refCr4%2FB5R6d3NTvL4f5W9tTlw%3D%3D%22%0D%0A%7D

{"name":"Unauthorized","message":"You are requesting with an invalid credential.","code":0,"status":401}
29 Lexey_
 
31.08.17
10:40
(28) Мойkey и Мойsign тоже кодируй, проверил, всё работает

Функция ВыполнитьЗапрос(АдресРесурса, ПараметрыЗапроса)

    СтрокаJSON = ОбщегоНазначенияКлиентСервер.СтруктураВJSON(ПараметрыЗапроса, Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет));
        
    ХД = Новый ХешированиеДанных(ХешФункция.SHA256);
    ХД.Добавить(МангоАТСПовтИсп.ApiKey());
    ХД.Добавить(СтрокаJSON);
    ХД.Добавить(МангоАТСПовтИсп.ApiSalt());
    sign = НРег(СтрЗаменить(ХД.ХешСумма, " ", ""));
    
    HTTPСоединение = Новый HTTPСоединение(МангоАТСПовтИсп.ApiServer(), 443,,,,, Новый ЗащищенноеСоединениеOpenSSL());
    
    СтрокаЗапроса = СтрШаблон("vpbx_api_key=%1&sign=%2&json=%3",
        КодироватьСтроку(МангоАТСПовтИсп.ApiKey(), СпособКодированияСтроки.КодировкаURL),
        КодироватьСтроку(sign, СпособКодированияСтроки.КодировкаURL),
        КодироватьСтроку(СтрокаJSON, СпособКодированияСтроки.КодировкаURL));
    
    ЗаголовкиHTTP = Новый Соответствие;
    ЗаголовкиHTTP.Вставить("Content-type", "application/x-www-form-urlencoded");
    HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, ЗаголовкиHTTP);
    HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаЗапроса);
    Возврат HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
        
КонецФункции
30 Lexey_
 
31.08.17
10:42
Функция ВыполнитьЗапрос(АдресРесурса, ПараметрыЗапроса)

    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку(Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет);
    ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапроса);
    СтрокаJSON = ЗаписьJSON.Закрыть();
        
    ХД = Новый ХешированиеДанных(ХешФункция.SHA256);
    ХД.Добавить(ApiKey);
    ХД.Добавить(СтрокаJSON);
    ХД.Добавить(ApiSalt);
    Sign = НРег(СтрЗаменить(ХД.ХешСумма, " ", ""));
    
    HTTPСоединение = Новый HTTPСоединение("app.mango-office.ru", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL());
    
    СтрокаЗапроса = СтрШаблон("vpbx_api_key=%1&sign=%2&json=%3",
        КодироватьСтроку(ApiKey, СпособКодированияСтроки.КодировкаURL),
        КодироватьСтроку(sign, СпособКодированияСтроки.КодировкаURL),
        КодироватьСтроку(СтрокаJSON, СпособКодированияСтроки.КодировкаURL));
    
    ЗаголовкиHTTP = Новый Соответствие;
    ЗаголовкиHTTP.Вставить("Content-type", "application/x-www-form-urlencoded");
    HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, ЗаголовкиHTTP);
    HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаЗапроса);
    Возврат HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
        
КонецФункции
31 Филиал-msk
 
31.08.17
11:20
Вот так вот сертифицированный специалист получил ещё один фрагмент кода, не приходя в сознание. Позже он попробует применить его в изменившемся окружении, фрагмент не сработает и он вернётся к нам с тем же вопросом и топаньем ножками (:
32 ILNIK19
 
31.08.17
11:21
(30) Спасибо большое за помощь.
Пробую ваш код, все равно не получается


Ключ = ПрисланныйКлюч;
ПараметрыЗапроса = Новый Структура;
    ПараметрыЗапроса.Вставить("key", Ключ);      

    HTTPОтвет = ВыполнитьЗапрос("vpbx/stats/result", ПараметрыЗапроса);
    
    Сообщить(HTTPОтвет.ПолучитьТелоКакСтроку("UTF-8"));

Функция ВыполнитьЗапрос(АдресРесурса, ПараметрыЗапроса)

    ApiKey  = "МойАпиКей";
    ApiSalt = "МойпиСалт";
    
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.УстановитьСтроку(Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Нет));
    ЗаписатьJSON(ЗаписьJSON, ПараметрыЗапроса);
    СтрокаJSON = ЗаписьJSON.Закрыть();
        
    ХД = Новый ХешированиеДанных(ХешФункция.SHA256);
    ХД.Добавить(ApiKey);
    ХД.Добавить(СтрокаJSON);
    ХД.Добавить(ApiSalt);
    Sign = НРег(СтрЗаменить(ХД.ХешСумма, " ", ""));
    
    HTTPСоединение = Новый HTTPСоединение("app.mango-office.ru", 443,,,,, Новый ЗащищенноеСоединениеOpenSSL());
    
    //СтрокаЗапроса = СтрШаблон("vpbx_api_key=%1&sign=%2&json=%3", ApiKey, Sign, СтрокаJSON);       //Включен режим совместимости 8.3.5
    СтрокаЗапроса = "vpbx_api_key="+КодироватьСтроку(ApiKey, СпособКодированияСтроки.КодировкаURL)+"&sign=" + КодироватьСтроку(Sign, СпособКодированияСтроки.КодировкаURL) + "&json=" + КодироватьСтроку(СтрокаJSON, СпособКодированияСтроки.КодировкаURL) + "";
    //СтрокаЗапроса = "vpbx_api_key="+ApiKey+"&sign=" + Sign + "&json=" + СтрокаJSON + "";
    
    Сообщить(СтрокаЗапроса);
    
    ЗаголовкиHTTP = Новый Соответствие;
    ЗаголовкиHTTP.Вставить("Content-type", "application/x-www-form-urlencoded");
    HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса, ЗаголовкиHTTP);
    HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаЗапроса);
    Возврат HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
        
КонецФункции

Отправляю запрос:
vpbx_api_key=МойАпиКей&sign=МойСигн&json=%7B%22key%22%3A%22npBHqNSot%2B56LITtFLmXBntHtRW0UieuljXQzda%2BRcKfOkJMaj%2B70w7VDMjbK2eullwcsAlL7Oq4okP9wzN64Q%3D%3D%22%7D

Ответ:
{"name":"Unauthorized","message":"You are requesting with an invalid credential.","code":0,"status":401}
33 ILNIK19
 
31.08.17
11:23
(31) Не мешай, раз не знаешь, как сделать
34 Филиал-msk
 
31.08.17
12:21
(33) Я переживаю. Как оно там, работает?
35 ILNIK19
 
31.08.17
12:34
Общаюсь с ТП Манго:
Проверьте пожалуйста сейчас:

Ключ v494KPOUaKTGH8ZmV/3PMrD/Db/tOHqr4edKmUgI/NiQxyxbWWJK3JS43MKKZsZxixtUQOkVslg95rOCLjmrLQ==
Запрос такой vpbx_api_key=МойApiKey&sign=МойSign&json=%7B%22key%22%3A%22v494KPOUaKTGH8ZmV%2F3PMrD%2FDb%2FtOHqr4edKmUgI%2FNiQxyxbWWJK3JS43MKKZsZxixtUQOkVslg95rOCLjmrLQ%3D%3D%22%7D
{"name":"Unauthorized","message":"You are requesting with an invalid credential.","code":0,"status":401}

Ответ ТП:

Вы получили {"key":"v494KPOUaKTGH8ZmV\/3PMrD\/Db\/tOHqr4edKmUgI\/NiQxyxbWWJK3JS43MKKZsZxixtUQOkVslg95rOCLjmrLQ=="}

Вы прислали {"key":"v494KPOUaKTGH8ZmV/3PMrD/Db/tOHqr4edKmUgI/NiQxyxbWWJK3JS43MKKZsZxixtUQOkVslg95rOCLjmrLQ=="}

Плюс еще нуль символ в параметре перед буквой v в самом начале

?vpbx_api_key": "МойApi"
36 ILNIK19
 
31.08.17
12:36
Символ слэша \ пропадает
37 ILNIK19
 
31.08.17
14:29
Короче победил.
Если используется кодировка UTF-8 при отправке запроса, то в начале контента 1с принудительно записывает BOM.
Нужно это отключить:

HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаЗапроса, "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);

И все взлетело.

Большое спасибо Lexey. Подал идею кодировки запроса в URL
38 Филиал-msk
 
31.08.17
15:22
(37) > Подал идею кодировки запроса в URL

Примерно 20 часов потребовалось сертифицированному специалисту, чтобы разобрать и понять собственные каракули из (3). Это успех! Поздравляю!
39 ILNIK19
 
31.08.17
15:46
(38) Задача решена, какая разница сколько времени это заняло? Я занимаюсь этим параллельно другими задачи.
Когда я сдавал сертификаты 10 лет назад, этих объектов и в помине не было. В следующий раз сделаю эту задачу за 10 минут.
А ты 20 часов только троллишь и мешаешь другим.
Ну продолжай в том же духе...
Беспричинное унижение других людей в интернете говорит о твоих проблемах в жизни и твоих комплексах. У меня нет времени на то, чтобы ублажать твое эго! Тебе с этим жить...
40 oleg_km
 
31.08.17
17:55
(39) Мда, доктор бы тебя так вылечил: кинул клич по форумам, кто-то что-то посоветовал, быстренько попробовал, ура поциент не умер.
Программист всегда исправляет последнюю ошибку.