Имя: Пароль:
1C
 
Отправка файла отчёта в MAX
0 yurikmellon2
 
03.04.26
10:43
Всем добрый день.
Коллеги, если есть, поделитесь рабочим кодом отправки файла в MAX, прости господи.
1 shuhard
 
03.04.26
10:46
2 yurikmellon2
 
03.04.26
10:49
(1) я так понимаю, что оба решения через GREEN-API. Так я умею. Напрямую через MAX API надо
3 mmg
 
03.04.26
10:54
4 yurikmellon2
 
03.04.26
11:00
(3) вот как раз по этой документации и пытаюсь сделать. Ссылку на загрузку получаю.
Дальше надо загрузить файл.
curl -X POST \
  -H "Content-Type: multipart/form-data" \
  -F "data=@movie.mp4" \
  "https://vu.mycdn.me/upload.do?sig={signature}&expires={timestamp}"

Что такое signature, что туда передавать?
5 Garykom
 
гуру
03.04.26
11:22
(4) случаем это не ЭЦП (точнее отпечаток-сигнатура файла) по ГОСТ через КриптоПРО?
https://xn----7sbmxacaqnu.xn--p1ai/news/kak_sozdat_sig_fajl_s%20pomoshchyu_kriptopro/
6 reg0303
 
03.04.26
11:24
(4) Эти параметры уже должны быть в ссылке на загрузку
7 Garykom
 
гуру
03.04.26
11:26
(6) дык это же загрузка файла видео в CDN от ВК
требуют указать криптохэш и время жизни файла видео
8 Garykom
 
гуру
03.04.26
11:27
(7)+ в ответ на загрузку вернется ссылка на видео, которую можно вставить в сообщение
9 picom
 
07.04.26
12:08
(4) Удалось направить файл и получить Токен вложения?
(8) Непонятно как его туда нормально загнать, пример бы

Это не работает
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
Файлы = Новый Массив;
Файлы.Добавить(Новый Структура("Имя, Данные, ИмяФайла", "data", ДвоичныеДанныеФайла, "1.txt"));
Результат = Коннектор.Post(ПутьДляЗагрузкиФайла, , Новый Структура("Файлы", Файлы));
10 picom
 
07.04.26
13:34
Есть подозрение что нужно использовать Сжатие GZip
Т.к. ответ приходит уже сжатый, а первые значения 1F 8B
11 yurikmellon2
 
13.04.26
09:50
Забыл отписаться. Исправляю упущение.
Рабочая процедура отправки файла в MAX.
ПутьКФайлу - путь к файлу во временном хранилище
IDЧата - это user_id пользователя
ТокенБота - токен бота

Чтобы отправлять не конкретному пользователю, а в группу, надо в этой стоке заменить user_id на chat_id
HTTPЗапросСообщения = Новый HTTPЗапрос("/messages?user_id=" + IDЧата, ЗаголовкиАвторизации);

Процедура ОтправитьФайлВMax(ПутьКФайлу, IDЧата, ТокенБота, ТипФайла = "file", ТекстСообщения = "") Экспорт
      ИмяФайла     = "ФайлОтчета_" + СтрЗаменить(ТекущаяДата(),":","") + ".xls";
      // Заголовки авторизации
      ЗаголовкиАвторизации = Новый Соответствие;
      ЗаголовкиАвторизации.Вставить("Authorization", ТокенБота);

      //Получаем URL для загрузки файла
      HTTPСоединение = Новый HTTPСоединение("platform-api.max.ru", 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
      HTTPЗапрос = Новый HTTPЗапрос("/uploads?type=file", ЗаголовкиАвторизации);
      
      // Отправляем POST запрос (пустое тело)
      HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
      Если HTTPОтвет.КодСостояния <> 200 Тогда
          ВызватьИсключение "Ошибка при получении URL для загрузки: " + HTTPОтвет.КодСостояния + " - " + HTTPОтвет.ПолучитьТелоКакСтроку();
      КонецЕсли;
      
      // Парсим JSON ответ
      ЧтениеJSON = Новый ЧтениеJSON;
      ЧтениеJSON.УстановитьСтроку(HTTPОтвет.ПолучитьТелоКакСтроку());
      ОтветМетаЗагрузки = ПрочитатьJSON(ЧтениеJSON);
      ЧтениеJSON.Закрыть();
      
      URLДляЗагрузки = ОтветМетаЗагрузки.url; // URL куда слать файл

      //Загружаем файл на полученный URL (Multipart/Form-Data)

      // Разбираем URL чтобы понять куда коннектиться
      РазборURL = СтрРазделить(URLДляЗагрузки, "/", Ложь);
      СерверЗагрузки = РазборURL[1]; // Например, storage.max.ru
      ПутьЗагрузки   = СтрЗаменить("/" + СтрСоединить(РазборURL, "/"),"/https:/fu.oneme.ru",""); // Остальная часть пути
      
      
      // Формируем Multipart тело запроса
      Boundary      = "----WebKitFormBoundary" + СтрЗаменить(Новый UUID, "-", "");
      ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
      
      // Строим тело запроса в памяти
      ПотокВПамяти = Новый ПотокВПамяти;
      ЗаписьДанных = Новый ЗаписьДанных(ПотокВПамяти);
      
      //Начало части (headers)
      ЗаписьДанных.ЗаписатьСтроку("--" + Boundary);
      ЗаписьДанных.ЗаписатьСтроку("Content-Disposition: form-data; name=""data""; filename=""" + ИмяФайла + """");
      ЗаписьДанных.ЗаписатьСтроку("Content-Type: application/octet-stream");
      ЗаписьДанных.ЗаписатьСтроку(""); // Пустая строка между заголовками и данными
      
      //Сам файл (бинарные данные)
      ЗаписьДанных.Записать(ДвоичныеДанныеФайла);
      ЗаписьДанных.ЗаписатьСтроку(""); // Перенос строки после файла
      
      //Конец запроса
      ЗаписьДанных.ЗаписатьСтроку("--" + Boundary + "--");
      
      ЗаписьДанных.Закрыть();
      ТелоЗапросаЗагрузки = ПотокВПамяти.ЗакрытьИПолучитьДвоичныеДанные();
      
      // Формируем HTTP запрос
      HTTPСоединениеЗагрузки = Новый HTTPСоединение(СерверЗагрузки, 443, , , , , Новый ЗащищенноеСоединениеOpenSSL());
      HTTPЗапросЗагрузки = Новый HTTPЗапрос(ПутьЗагрузки);
      HTTPЗапросЗагрузки.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Boundary);
      HTTPЗапросЗагрузки.УстановитьТелоИзДвоичныхДанных(ТелоЗапросаЗагрузки);
      
      HTTPОтветЗагрузки = HTTPСоединениеЗагрузки.ОтправитьДляОбработки(HTTPЗапросЗагрузки);
      
      Если HTTPОтветЗагрузки.КодСостояния <> 200 Тогда
          ВызватьИсключение "Ошибка при загрузке файла: " + HTTPОтветЗагрузки.КодСостояния;
      КонецЕсли;
      
      // Парсим ответ загрузки (информация о файле)
      ЧтениеJSON.УстановитьСтроку(HTTPОтветЗагрузки.ПолучитьТелоКакСтроку());
      ДанныеФайла = ПрочитатьJSON(ЧтениеJSON);
      ЧтениеJSON.Закрыть();

         //тут нужна пауза, видимо файл не успевает записаться. Без паузы валит ошибку
     //Ошибка отправки сообщения: {"code":"attachment.not.ready","message":"Key: errors.process.attachment.file.not.processed"}      
     //с паузой всё норм
      ДатаКон = ТекущаяДата() + 1;//1 секундой больше
      Пока ТекущаяДата() < ДатаКон Цикл
      КонецЦикла;      
      
      //ВызватьПаузу(1000);

      //Отправляем сообщение с вложением
      HTTPЗапросСообщения = Новый HTTPЗапрос("/messages?user_id=" + IDЧата, ЗаголовкиАвторизации);
      HTTPЗапросСообщения.Заголовки.Вставить("Content-Type", "application/json");
      
      // Формируем JSON тело
      ЗаписьJSON = Новый ЗаписьJSON;
      ЗаписьJSON.УстановитьСтроку();
      ЗаписьJSON.ЗаписатьНачалоОбъекта();
      ЗаписьJSON.ЗаписатьИмяСвойства("text");
      ЗаписьJSON.ЗаписатьЗначение("Отправляю файл");
      
      ЗаписьJSON.ЗаписатьИмяСвойства("attachments");
      ЗаписьJSON.ЗаписатьНачалоМассива();
      ЗаписьJSON.ЗаписатьНачалоОбъекта();
      ЗаписьJSON.ЗаписатьИмяСвойства("type");
      ЗаписьJSON.ЗаписатьЗначение("file");
      
      // В payload записываем весь объект, полученный на шаге 2
      ЗаписьJSON.ЗаписатьИмяСвойства("payload");
      ЗаписатьJSON(ЗаписьJSON, ДанныеФайла);
      ЗаписьJSON.ЗаписатьКонецОбъекта();
      ЗаписьJSON.ЗаписатьКонецМассива();
      ЗаписьJSON.ЗаписатьКонецОбъекта();
      
      СтрокаТелаЗапроса = ЗаписьJSON.Закрыть();
      HTTPЗапросСообщения.УстановитьТелоИзСтроки(СтрокаТелаЗапроса, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
      
      HTTPОтветСообщения = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапросСообщения);
      
      Если HTTPОтветСообщения.КодСостояния = 200 Тогда
          Сообщить("Файл успешно отправлен!");
      Иначе
          Сообщить("Ошибка отправки сообщения: " + HTTPОтветСообщения.ПолучитьТелоКакСтроку());
      КонецЕсли;
  
КонецПроцедуры
12 Stepashkin
 
13.04.26
10:16
Пригодится.
13 skafandr
 
13.04.26
11:53
(13) Спасибки. А вдруг тоже придется прикоснуться к прекрасному :-(
14 VKS
 
13.04.26
17:20
Пользуясь случаем спрошу кто работает с макс. Как в групповом чате через api упомянуть пользователя?
В телеграмм было через ИмяПользователя, а тут не выходит
Компьютеры — прекрасное средство для решения проблем, которых до их появления не было.