При отправке HTTP-запросов из 1С к сторонним веб-сервисам часто требуется передавать специальные заголовки, например, Referer или User-Agent. Однако разработчики нередко сталкиваются с ситуацией, когда при передаче URL с указанием протокола (http:// или https://) платформа 1С выдает системную ошибку: "ошибка в параметре №3" (или аналогичную ошибку параметров метода).
В этой статье разберем причину возникновения данной проблемы, рассмотрим правильный способ передачи HTTP-заголовков через объект Соответствие, а также проанализируем важные нюансы работы с соединением и альтернативные механизмы отправки запросов.
Рассмотрим, как изначально формировался запрос. В устаревших примерах кода заголовки запроса часто передаются в виде единой текстовой строки, где пары «Ключ: Значение» разделяются символами переноса строк Символы.ВК + Символы.ПС:
// Некорректный подход к формированию заголовков строкой
ЗаголовкиСтрокой = "Accept: text/html" + Символы.ВК + Символы.ПС +
"Referer: http://example.com/page.html" + Символы.ВК + Символы.ПС +
"Connection: keep-alive";
HTTPСоединение = Новый HTTPСоединение("example.com");
HTTPСоединение.Получить("/dir/file.ext", ИмяФайла, ЗаголовкиСтрокой);
При передаче заголовков строкой встроенный парсер платформы 1С разбивает текст по парам, ориентируясь на символы переноса строк и первое найденное двоеточие. Когда в значении заголовка Referer встречается строка http://, дополнительное двоеточие и слэши сбивают алгоритм текстового разбора платформы. В результате 1С не может корректно разобрать третьей параметр метода Получить и выдает ошибку.
Для исключения ошибок парсинга передавайте заголовки HTTP-запроса не строкой, а специализированным объектом Соответствие. В этом случае ключевые пары четко разделены на уровне структуры данных 1С, и платформа не выполняет опасную текстовую интерпретацию.
Разберем по шагам правильный алгоритм формирования запроса:
Соответствие.Вставить("ИмяЗаголовка", "ЗначениеЗаголовка").Получить или Записать объекта HTTPСоединение.Посмотрим на пример правильной реализации:
// Формируем структуры заголовков через объект Соответствие
ЗаголовкиЗапроса = Новый Соответствие;
ЗаголовкиЗапроса.Вставить("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
ЗаголовкиЗапроса.Вставить("Accept-Language", "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3");
ЗаголовкиЗапроса.Вставить("Referer", "http://example.com/dir/page.jsp");
ЗаголовкиЗапроса.Вставить("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
Сервер = "stupid.com";
ПутьНаСервере = "/dir/file.jsp";
ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
Соединение = Новый HTTPСоединение(Сервер);
Соединение.Получить(ПутьНаСервере, ИмяВременногоФайла, ЗаголовкиЗапроса);
Использование Соответствие полностью решает проблему с передачей двоеточий, слэшей и других спецсимволов в значении Referer.
У разработчиков часто возникает вопрос: закрывается ли сетевое соединение с сервером сразу после выполнения метода Получить или держится открытым?
Ответ заключается в следующем: TCP-соединение с веб-сервером удерживается открытым всё то время, пока активна переменная, содержащая объект HTTPСоединение. Автоматическое закрытие сокета происходит в момент очистки переменной или при выходе из области видимости (например, при завершении работы процедуры). Для явного освобождения ресурсов переменной можно присвоить неопределенное значение:
Соединение = Неопределено;
Проанализируем дополнительные подводные камни, с которыми можно столкнуться при выгрузке файлов с веб-серверов:
Accept-Encoding: gzip, deflate вручную при сохранении ответа напрямую в файл через объект HTTPСоединение. Если сервер вернет сжатый поток данных, платформа 8.2 не распакует его автоматически, и в итоговый файл закроется сжатый бинарный архив, который система может посчитать поврежденным.Referer) на новый URL. В таком случае требуется сначала проанализировать заголовок Location из ответа и выполнить повторный запрос по новому URL.
Заголовки = Новый Соответствие;
Заголовки.Вставить("Referer", "http://example.com/page");
Запрос = Новый HTTPЗапрос("/dir/file.jsp", Заголовки);
Соединение = Новый HTTPСоединение("stupid.com");
Ответ = Соединение.Получить(Запрос, ИмяВременногоФайла);
Referer можно решить через системный COM-объект Windows:
HTTP = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
HTTP.Open("GET", "http://stupid.com/dir/file.jsp", Ложь);
HTTP.SetRequestHeader("Referer", "http://example.com/page");
HTTP.Send();
Если HTTP.Status = 200 Тогда
Stream = Новый COMОбъект("ADODB.Stream");
Stream.Type = 1; // Binary
Stream.Open();
Stream.Write(HTTP.ResponseBody);
Stream.SaveToFile(ИмяВременногоФайла, 2);
Stream.Close();
КонецЕсли;
Таким образом, использование объекта Соответствие является наилучшей практикой для формирования HTTP-заголовков в 1С, так как исключает синтаксические ошибки платформы при парсинге сложных значений URL.