При разработке и эксплуатации HTTP-сервисов на платформе 1С:Предприятие программисты часто сталкиваются с ситуацией, когда при повторном вызове метода GET система возвращает старый ответ, хотя данные в информационной базе уже изменились. Особенно сбивает с толку тот факт, что в Журнале Регистрации 1С повторный запрос может даже не отображаться. Это явный признак того, что запрос «оседает» где-то на промежуточном уровне. В этой статье мы подробно разберем, почему это происходит, как работают механизмы кэширования и что нужно сделать, чтобы гарантированно получать актуальные данные.
Когда внешняя система (например, конфигурация 1С 7.7, 10.3 или стороннее приложение) обращается к HTTP-сервису 1С, запрос проходит через несколько этапов. Если запрос типа GET выполняется повторно с теми же параметрами, ответ может быть возвращен из кэша. Существует три основных места, где может происходить кэширование:
w3wp.exe и не заходя в саму базу 1С.Проанализируем ситуацию: если в Журнале Регистрации нет записи о входящем соединении, значит, запрос «застрял» на веб-сервере или клиенте. Выясним, как с этим бороться.
Согласно протоколу HTTP, сервер может управлять поведением кэша с помощью специальных заголовков в ответе. Если мы хотим сказать всем посредникам и клиенту, что данные нельзя кэшировать, нам нужно правильно сформировать HTTPСервисОтвет.
Рассмотрим пример кода на стороне сервера (в модуле HTTP-сервиса), который принудительно отключает кэширование:
Ответ = Новый HTTPСервисОтвет(200);
// Указываем, что контент динамический
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
// Запрещаем кэширование всеми доступными способами
// no-store: не сохранять в кэш вообще
// no-cache: обязательно проверять свежесть на сервере
// must-revalidate: если кэш устарел, обязательно переспросить сервер
Ответ.Заголовки.Вставить("Cache-Control", "no-store, no-cache, must-revalidate");
// Для старых прокси-серверов (HTTP/1.0)
Ответ.Заголовки.Вставить("Pragma", "no-cache");
// Устанавливаем дату истечения в прошлом (1970 год)
Ответ.Заголовки.Вставить("Expires", "Thu, 01 Jan 1970 00:00:00 GMT");
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
// Формируем данные
Данные = Новый Структура("Результат, ТекущееВремя", "ОК", ТекущаяДата());
ЗаписатьJSON(ЗаписьJSON, Данные);
Ответ.УстановитьТелоИзСтроки(ЗаписьJSON.Закрыть());
Возврат Ответ;
Важный нюанс: Иногда веб-сервер IIS может игнорировать заголовки, добавленные из кода 1С, или вырезать их при определенных настройках безопасности. Поэтому, если программный метод не помог, переходим к настройкам сервера.
Если вы используете Internet Information Services (IIS), посмотрите на настройки «Кэширование вывода» (Output Caching). По умолчанию IIS может пытаться оптимизировать работу, кэшируя ответы от расширений .dll. Поскольку публикация 1С работает через isapi_1c8.dll (или wsapvr.dll), IIS может ошибочно считать ответы статичными.
Выполним следующие шаги для отключения кэша в консоли IIS:
* или для путей вашего сервиса, их стоит удалить или изменить.Также можно внести изменения напрямую в файл web.config вашей публикации, добавив в секцию <system.webServer> следующую строку:
<configuration>
<system.webServer>
<caching enabled="false" />
</system.webServer>
</configuration>
Это гарантирует, что IIS не будет пытаться сохранить ответ в своей памяти.
В архитектуре REST метод GET считается «идемпотентным» и «безопасным», что по умолчанию дает право всем сетевым узлам кэшировать его результат. Метод POST, напротив, предназначен для изменения состояния сервера, и его ответы по спецификации RFC практически никогда не кэшируются автоматически.
Если ваша задача позволяет отойти от строгих канонов REST и вам нужно гарантированно получать свежие данные без настройки веб-сервера, попробуйте просто заменить тип запроса. Рассмотрим, как изменится код вызова в 1С (клиентская часть):
// Вместо .Получить() используем .ОтправитьДляОбработки()
HTTPСоединение = Новый HTTPСоединение(Сервер, , , , , 5);
HTTPЗапрос = Новый HTTPЗапрос("/hs/my_service/v1/get_data");
// Даже если тело пустое, POST заставит сервер отработать честно
HTTPЗапрос.УстановитьТелоИзСтроки("{}");
HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Это решение часто называют «костылем», но в корпоративных сетях со сложной структурой прокси-серверов оно является самым надежным.
Если вы обязаны использовать GET, но кэш все равно мешает, применим проверенный метод из веб-разработки — добавление в строку запроса изменяющегося параметра, который сервер 1С будет просто игнорировать.
Посмотрим на пример формирования URL:
// Добавляем к адресу случайное число или метку времени
УникальныйКлюч = Формат(ТекущаяУниверсальнаяДатаВМиллисекундах(), "ЧГ=0");
АдресРесурса = "/hs/my_service/v1/get_data?nocache=" + УникальныйКлюч;
HTTPЗапрос = Новый HTTPЗапрос(АдресРесурса);
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);
Для любого кэширующего прокси-сервера или самого IIS запрос с новым параметром в URL — это совершенно новый запрос. Он обязан передать его в 1С, так как не имеет в своей базе данных ответа для такого точного адреса. Это самый простой и эффективный способ «пробить» любой кэш без прав администратора на сервере.
Подведем итог нашему исследованию. Если ваш HTTP-сервис в 1С возвращает старые данные, действуйте по алгоритму:
Cache-Control: no-store и Expires в прошлом времени.Output Caching для публикации 1С.?t=63845...) или перейдите на метод POST.Помните, что кэширование — это полезный инструмент для высоконагруженных систем, но в учетных системах на базе 1С актуальность данных почти всегда важнее скорости отдачи ответа веб-сервером.