Как узнать размер отправляемого из 1С POST-запроса и решить проблему нехватки памяти при выгрузке картинок на сайт

Программист 1С v8.3 (Управляемые формы) Торговля и дистрибуция
← На главную

При интеграции 1С с интернет-магазинами (например, на движке Shop-Script/Webasyst, Bitrix или OpenCart) одной из наиболее частых проблем является аварийное завершение работы системы при передаче больших объемов данных. Ситуация усугубляется, если выгружается не просто текстовый каталог (номенклатура, цены, остатки), а тяжелые медиафайлы — изображения товаров. База данных объемом в несколько гигабайт и каталог на десятки тысяч позиций с картинками могут легко переполнить оперативную память сервера 1С, вызывая ошибку "Недостаточно памяти" или аварийно завершая рабочий процесс rphost.exe.

В этой статье мы подробно разберем, как определить точный размер передаваемого POST-запроса (архива с данными), почему стандартное разбиение на порции в настройках обмена часто не помогает решить проблему с памятью, и какие системные и программные шаги необходимо предпринять для стабильной работы выгрузки.

Способ 1. Определение размера POST-запроса с помощью утилит мониторинга трафика (Fiddler)

Если нам необходимо узнать точный размер сформированного пакета непосредственно «в полете», то есть при его отправке на веб-сервер сайта, использование специализированных локальных прокси-серверов является лучшим решением. Рассмотрим этот процесс по шагам на примере программы Fiddler:

  1. Скачаем и установим бесплатный HTTP-сниффер Fiddler (или его современную версию Fiddler Everywhere) на компьютер, где запускается сеанс выгрузки 1С.
  2. Запустим Fiddler перед началом процесса обмена в 1С. Утилита начнет автоматически перехватывать все исходящие HTTP- и HTTPS-запросы системы.
  3. Если обмен идет по защищенному протоколу HTTPS, в настройках Fiddler (меню Tools -> Options -> HTTPS) обязательно включим опцию "Decrypt HTTPS traffic" и установим корневой сертификат безопасности Fiddler в систему, иначе программа не сможет расшифровать тело запроса.
  4. Запустим выгрузку из 1С. В левом окне Fiddler мы увидим список отправляемых запросов. Нам нужен запрос со следующим методом: POST, направленный на адрес скрипта импорта вашего сайта.
  5. Выберем этот запрос кликом мыши. В правой панели перейдем на вкладку Inspectors, а затем на вкладку Headers.
  6. В разделе заголовков найдем строку Content-Length. Значение напротив этого параметра указывает точный размер передаваемого POST-запроса (и, соответственно, упакованного zip-архива) в байтах. Разделив это число на 1024 последовательно два раза, мы получим точный вес файла в мегабайтах.

Способ 2. Программное определение размера архива в коде 1С

Если у нас есть доступ к конфигуратору 1С и коду обработки обмена, мы можем узнать размер отправляемого архива программно, записав данные в Журнал регистрации. Для этого найдем место в коде, где инициализируется отправка HTTP-соединения и создается временный zip-файл на диске (обычно с помощью объекта ЗаписьZipФайла).

Давайте посмотрим на практический пример кода, который определяет размер временного файла перед отправкой:


// ПутьКФайлуАрхива - это переменная, содержащая путь к сформированному ZIP-файлу на диске
ВыгружаемыйФайл = Новый Файл(ПутьКФайлуАрхива);

Если ВыгружаемыйФайл.Существует() Тогда
    РазмерВБайтах = ВыгружаемыйФайл.Размер();
    РазмерВМегабайтах = Окр(РазмерВБайтах / 1024 / 1024, 2);
    
    // Записываем информацию в Журнал регистрации для последующего анализа
    ЗаписьЖурналаРегистрации(
        "Интеграция.ОбменССайтом",
        УровеньЖурналаРегистрации.Информация,
        ,
        ,
        "Подготовлен пакет обмена. Имя файла: " + ВыгружаемыйФайл.Имя + 
        ". Размер: " + РазмерВМегабайтах + " МБ."
    );
КонецЕсли;

Если же данные не записываются во временный файл на диске, а формируются непосредственно в оперативной памяти в виде двоичных данных, мы можем использовать встроенный метод Размер() объекта ДвоичныеДанные:


// ДвоичныеДанныеАрхива - объект, содержащий упакованный архив в памяти
РазмерВБайтах = ДвоичныеДанныеАрхива.Размер();
РазмерВМегабайтах = Окр(РазмерВБайтах / 1024 / 1024, 2);
Сообщить("Размер отправляемого буфера: " + РазмерВМегабайтах + " МБ.");

Выясняем скрытую причину переполнения памяти при выгрузке

Часто пользователи сталкиваются со странным поведением системы: даже при ограничении размера порции (например, выгружать по 5–10 товаров за один раз) сервер 1С все равно потребляет до 99% оперативной памяти и падает. Выясним причину этой проблемы.

Дело в том, что настройка «размер порции» в стандартных модулях обмена чаще всего влияет только на физическую отправку пакетов на сайт, но не на процесс подготовки данных в самой 1С. Перед тем как начать деление товаров на порции, обработка обмена может выполнять один глобальный запрос к базе данных, пытаясь получить всю информацию о номенклатуре и связанных картинках.

Изображения в 1С хранятся в виде двоичных данных (тип ХранилищеЗначений) прямо внутри таблиц базы данных. При выполнении неоптимизированного запроса сервер 1С (процесс rphost.exe) пытается прочитать и удержать в оперативной памяти бинарные файлы тысяч картинок одновременно. В процессе сериализации (подготовки картинок к отправке, перевода их в формат Base64 или сжатия в zip) данные дублируются в памяти несколько раз. В результате 8 ГБ оперативной памяти сервера мгновенно исчерпываются, даже если на сайт в данный момент передается пачка всего из 5 товаров.

Решение 1. Переход на 64-разрядную платформу 1С

Это важнейший шаг, без выполнения которого любые оптимизации кода могут оказаться бесполезными. Проанализируем разницу между разрядностями платформ:

Рекомендация: Установите 64-битный сервер приложений 1С и используйте 64-битный клиент для выполнения «тяжелых» процедур обмена.

Решение 2. Хранение файлов картинок в томах на диске

Хранение картинок внутри тела самой базы данных (в СУБД или файле 1CD) значительно увеличивает нагрузку на дисковую подсистему и оперативную память при любых операциях чтения. Мы настоятельно рекомендуем настроить хранение присоединенных файлов вне информационной базы:

  1. Перейдем в раздел Администрирование -> Настройки работы с файлами.
  2. Установим флаг "Хранить файлы в томах на диске".
  3. Создадим и настроим тома хранения файлов (укажем сетевой путь или локальную папку на сервере с достаточным объемом свободного места).
  4. Запустим типовую обработку переноса файлов в тома.

После переноса картинок в тома СУБД перестанет раздуваться, а платформа 1С при формировании выгрузки будет последовательно считывать файлы с жесткого диска, не загружая тяжелые бинарные объекты в оперативную память через СУБД.

Решение 3. Оптимизация программного кода выгрузки картинок

Если выгрузка пишется или дорабатывается вручную, критически важно переписать алгоритм так, чтобы выборка картинок происходила порционно, исключая их одновременное нахождение в памяти. Разберем правильный шаблон порционной обработки:


// ПРИМЕР ОПТИМИЗИРОВАННОГО ПОДХОДА
// Вместо одного запроса ко всей номенклатуре делаем порционный обход

РазмерПорции = 100;
ТекущийОфсет = 0;

Пока Истина Цикл
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ " + Строка(РазмерПорции) + "
        |	Номенклатура.Ссылка КАК Ссылка,
        |	Номенклатура.ФайлКартинки КАК ФайлКартинки
        |ИЗ
        |	Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |	Номенклатура.ЭтоГруппа = ЛОЖЬ
        |	И Номенклатура.Ссылка ВЫБОРКА_ПО_ПОРЦИЯМ (Используйте фильтрацию по коду или ID)";
        
    // Примечание: Для корректной порционной выборки используйте фильтрацию по ID больше предыдущего
    // в целях упрощения примера логика смещения опущена.
    
    РезультатЗапроса = Запрос.Выполнить();
    Если РезультатЗапроса.Пустой() Тогда
        Прервать; // Все товары обработаны
    КонецЕсли;
    
    Выборка = РезультатЗапроса.Выбрать();
    Пока Выборка.Следующий() Цикл
        // Обрабатываем строго одну картинку, упаковываем ее и сразу очищаем переменные
        ДвоичныеДанныеФайла = ПолучитьДвоичныеДанныеФайла(Выборка.ФайлКартинки);
        Если ДвоичныеДанныеФайла <> Неопределено Тогда
            ЗаписатьФайлВАрхив(ДвоичныеДанныеФайла, Выборка.Ссылка.Код);
        КонецЕсли;
        
        // Принудительно освобождаем память от тяжелых двоичных данных
        ДвоичныеДанныеФайла = Неопределено;
    КонецЦикла;
    
    // Отправляем сформированную небольшую порцию на сайт
    ОтправитьПакетНаСайт();
    ОчиститьВременныйКаталогПакетногоОбмена();
    
КонецЦикла;

Решение 4. Оптимизация разрешения изображений

Очень часто контент-менеджеры загружают в 1С оригинальные фотографии товаров прямо с камер или фотостоков объемом 10–15 Мегабайт и разрешением свыше 5000 пикселей. Такое разрешение избыточно для сайта интернет-магазина и только перегружает серверы.

Мы можем встроить механизм автоматического сжатия изображений прямо перед их отправкой в zip-архив с помощью встроенных возможностей платформы 1С:


// Сжатие картинки "на лету" перед упаковкой
ИсходнаяКартинка = Новый Картинка(ПутьКФайлуНаДиске);

// Если картинка слишком большая, преобразуем ее разрешение
Если ИсходнаяКартинка.Ширина() > 1200 Или ИсходнаяКартинка.Высота() > 1200 Тогда
    // Платформа выполнит масштабирование с сохранением пропорций
    СжатаяКартинка = ИсходнаяКартинка.Преобразовать(ФорматКартинки.JPEG, 1200, 1200);
    СжатаяКартинка.Записать(ПутьКВременномуФайлуСжатия);
КонецЕсли;

Решение 5. Настройка веб-сервера и PHP на стороне сайта

Даже если 1С успешно сформирует большой архив и отправит его без падения по памяти, принимающий веб-сервер сайта (Shop-Script) может заблокировать такой POST-запрос. Чтобы этого не произошло, необходимо проверить и скорректировать следующие параметры на хостинге или выделенном сервере сайта:

  1. В конфигурации Nginx (nginx.conf):

    Параметр client_max_body_size 256M; (установите лимит в соответствии с максимально возможным весом вашего zip-пакета, например, 256 или 512 Мегабайт, иначе сервер вернет ошибку 413 Request Entity Too Large).

  2. В конфигурации PHP (php.ini):
    • post_max_size = 256M (максимально допустимый размер данных, отправляемых методом POST).
    • upload_max_filesize = 256M (максимальный размер загружаемого файла).
    • memory_limit = 512M (объем оперативной памяти, выделяемый PHP-скрипту для распаковки и обработки архива на сайте).
    • max_execution_time = 300 (время выполнения скрипта в секундах, так как импорт большого количества изображений требует времени).

Таким образом, решив проблему комплексно — проверив размер отправляемого пакета с помощью Fiddler, перейдя на x64-разрядную версию платформы 1С, перенеся хранение файлов в тома на диске и ограничив аппетиты системы к оперативной памяти при помощи порционной обработки кода, мы получим стабильный и быстрый обмен данными с сайтом без сбоев и зависаний.

← На главную