При работе с современными API из среды 1С:Предприятие 7.7 программисты часто сталкиваются с тем, что вместо привычного кириллического текста программа возвращает набор знаков вопроса (????). Особенно это заметно при получении данных в формате JSON или XML, где используется кодировка UTF-8. В этой статье мы подробно разберем, почему это происходит, как работают кодировки в «семерке» и какими способами можно добиться корректного отображения русских букв.
Давайте проанализируем ситуацию, описанную в теме. Основная причина кроется в архитектуре платформы 1С 7.7. Она является ANSI-приложением, то есть изначально не умеет работать с Unicode (UTF-8) напрямую. Когда мы используем объект WinHttp.WinHttpRequest.5.1 и обращаемся к свойству ResponseText, происходит следующее:
WinHttp получает от сервера поток байтов в кодировке UTF-8.ResponseText объект пытается автоматически преобразовать этот поток в системную кодировку Windows (обычно Windows-1251 для русской локализации).Важное наблюдение автора темы: вместо двух русских букв «УТ» приходит четыре знака вопроса. Это прямое доказательство того, что данные приходят в UTF-8. В этой кодировке одна русская буква занимает 2 байта. Слово «УТ» — это 4 байта. Система пытается интерпретировать каждый байт как отдельный символ в кодировке 1251, не находит соответствия и заменяет их символами с кодом 63 (знак вопроса).
Рассмотрим код, который часто пытаются использовать новички, и разберем, почему он не помогает:
пОбъект = СоздатьОбъект("WinHttp.WinHttpRequest.5.1");
пОбъект.Option(2, "utf-8"); // Это не влияет на кодировку ответа!
Как справедливо отмечено в обсуждении, настройка Option(2) (равная WinHttpRequestOption_UrlCodePage) отвечает только за кодирование самого URL-адреса запроса. Она никак не указывает серверу, в какой кодировке присылать ответ, и не помогает объекту WinHttp интерпретировать тело ответа. Настройки реестра (замена 1252 на c_1251.nls) также помогают только отображать шрифты в интерфейсе, но не решают проблему программной обработки байтового потока.
Первым делом мы можем попытаться «попросить» сервер прислать ответ в нужной нам кодировке Windows-1251. Для этого используются HTTP-заголовки. Проанализируем, какие заголовки стоит добавить в ваш запрос:
пОбъект.Open("POST", УРЛСтрокаМетода, 0);
// Указываем, какие кодировки мы готовы принять
пОбъект.setRequestHeader("Accept-Charset", "windows-1251, utf-8;q=0.7, *;q=0.7");
// Указываем тип контента и желаемую кодировку
пОбъект.setRequestHeader("Content-Type", "application/json; charset=windows-1251");
Однако стоит учитывать, что современные API (например, интеграции с маркетплейсами или государственными системами) часто жестко зафиксированы на стандарте UTF-8 и могут проигнорировать ваш заголовок Accept-Charset.
Это самый надежный и правильный метод для 1С 7.7. Вместо того чтобы позволять объекту WinHttp самостоятельно портить текст через ResponseText, мы заберем «сырые» бинарные данные через ResponseBody и перекодируем их вручную с помощью объекта ADODB.Stream.
Разберем этот процесс по шагам:
ADODB.Stream.Пример реализации функции для корректного чтения ответа:
// Функция получает объект WinHttp после выполнения метода Send()
Функция ПолучитьТекстИзОтвета(пОбъект)
Перем Результат;
// Используем ADODB.Stream для конвертации
Поток = СоздатьОбъект("ADODB.Stream");
Поток.Type = 1; // Тип - бинарный
Поток.Open();
// Записываем бинарное тело ответа в поток
Поток.Write(пОбъект.ResponseBody);
// Перематываем в начало и меняем режим на текстовый
Поток.Position = 0;
Поток.Type = 2; // Тип - текстовый
Поток.Charset = "utf-8"; // Указываем, что в потоке данные UTF-8
// Теперь ReadText вернет строку, понятную для 1С 7.7
Результат = Поток.ReadText();
Поток.Close();
Возврат Результат;
КонецФункции
Этот метод позволяет избежать появления «вопросиков», так как 1С получает данные уже после того, как специализированный объект ADODB корректно сопоставил двухбайтовые символы UTF-8 с их аналогами в системной таблице.
Если по каким-то причинам использование ADODB.Stream неудобно, можно воспользоваться внешним скриптом через MSScriptControl.ScriptControl. Сценарии внутри этого объекта работают в среде, которая лучше справляется с Unicode.
Рассмотрим логику: мы передаем бинарный объект в функцию на VBScript, которая выполняет преобразование. Как упоминалось в сообщении форума, это позволяет «завернуть» всю работу с HTTP во внешний скрипт, возвращая в 1С уже чистую ANSI-строку.
Скрипт = СоздатьОбъект("MSScriptControl.ScriptControl");
Скрипт.Language = "VBScript";
Скрипт.AddCode("
|Function ConvertToAnsi(BinaryData)
| Dim Stream
| Set Stream = CreateObject(""ADODB.Stream"")
| Stream.Type = 1 'Binary
| Stream.Open
| Stream.Write BinaryData
| Stream.Position = 0
| Stream.Type = 2 'Text
| Stream.Charset = ""utf-8""
| ConvertToAnsi = Stream.ReadText
| Stream.Close
|End Function
|");
// Вызов функции: ТекстОтвета = Скрипт.Run("ConvertToAnsi", пОбъект.ResponseBody);
Проанализируем еще несколько моментов, которые могут встретиться при работе:
EF BB BF). ADODB.Stream обычно корректно их обрабатывает, но если вы видите странный символ в самом начале строки, его стоит удалять принудительно.MSXML2.DOMDocument умеет загружать данные напрямую из потока. Использование пОбъектDOM.load(пОбъектWinHttp.ResponseStream) автоматически решит проблему кодировки без использования дополнительных функций.Таким образом, мы выяснили, что причина «вопросиков» — это попытка 1С 7.7 прочитать UTF-8 как обычный текст. Чтобы решить проблему, всегда используйте ResponseBody и конвертируйте его через ADODB.Stream.