Skip to main content
Создаёт пользовательский HTTP-обработчик, определённый в SQL, без изменения файла конфигурации сервера. Обработчики, определённые в SQL, служат альтернативой обработчикам HTTP-интерфейса, настраиваемым в конфигурации.

Синтаксис

Создаёт обработчик с указанным name. Имя используется для управления обработчиками с помощью SQL-запросов, в диагностических сообщениях и для определения порядка обработчиков.

Секции

  • PROTOCOL — необязательный. Если указано имя протокола, обработчик активен только для указанного компонуемого протокола. В противном случае обработчик активен на всех HTTP-конечных точках: встроенных портах http/https и всех слушателях компонуемых протоколов HTTP-типа. PROTOCOL ANY явно выбирает это поведение по умолчанию; в ALTER HANDLER он снимает ранее установленное ограничение протокола. На протокол, буквально называемый any, можно сослаться с помощью обратных кавычек: PROTOCOL `any` .
  • URL — обязательный. Может иметь вид точного URL, URL PREFIX или URL REGEXP. Для точных URL и префиксов неоднозначность проверяется при создании или изменении, и при её наличии генерируется исключение. Для регулярных выражений проверить неоднозначность невозможно. URL сопоставляется без строки запроса после ? и идентификатора фрагмента после #. URL PREFIX сопоставляется как базовый путь на границе сегмента пути — с той же семантикой, что и правило url_prefix у обработчиков, заданных конфигурацией: URL PREFIX '/api/v1' соответствует /api/v1, /api/v1/ и /api/v1/write, но не /api/v1beta. Завершающий символ / в префиксе игнорируется, поэтому '/api/v1/' и '/api/v1' работают одинаково.
  • METHODS — необязательный. Список разрешённых HTTP-методов. По умолчанию разрешён только GET. Поддерживаются методы GET, POST, PUT и DELETE. Модифицирующие методы POST, PUT и DELETE позволяют выполнять запросы, изменяющие данные; безопасные методы, такие как GET и HEAD, всегда выполняются в режиме readonly. Следовательно, обработчик, запрос которого изменяет данные (например, INSERT или DDL), должен разрешать хотя бы один модифицирующий метод — при создании такого обработчика только с методами только для чтения (например, с GET по умолчанию) генерируется исключение. Особый случай составляют запросы, побочные эффекты которых сохраняются в режиме readonly: BACKUP и RESTORE имеют долговременные побочные эффекты, изменяющие сеанс операторы SET, SET ROLE, USE, BEGIN TRANSACTION, COMMIT, ROLLBACK и SET TRANSACTION SNAPSHOT изменяют состояние сеанса или транзакции, сохраняющееся между запросами при использовании session_id, а CREATE TEMPORARY TABLE / CREATE TEMPORARY VIEW создают объект, существующий в сеансе, — однако режим readonly безопасных методов не блокирует ни один из них. Изменения существующей временной таблицы также не блокируются режимом readonly, поэтому запросы, которые могут обращаться к такой таблице, обрабатываются аналогично: INSERT, целевая таблица которого не указана с базой данных (неквалифицированное имя может разрешиться во временную таблицу сеанса), DROP TEMPORARY TABLE, DROP TABLE / TRUNCATE TABLE таблицы без указания базы данных и ALTER таблицы без указания базы данных (ALTER TEMPORARY TABLE — тот же оператор). Целевая таблица с указанием базы данных никогда не может быть временной, поэтому такие запросы не подпадают под это правило. HTTP требует, чтобы безопасные методы не имели побочных эффектов (обработчик, объявленный для GET, также обслуживается для HEAD, при котором тело ответа не возвращается, и эффект был бы незаметен). Поэтому обработчик, выполняющий такой запрос, должен указывать только модифицирующие методы — при его создании или изменении с добавлением безопасного метода генерируется исключение. Составные операторы анализируются по вложенным операторам: для statement1 PARALLEL WITH statement2 ... и EXECUTE AS <user> <statement> приведённые выше правила применяются к вложенным операторам, поскольку выполняются именно они (каждый в копии контекста обработчика, сохраняющей режим readonly). Отдельный EXECUTE AS <user> заставляет весь сеанс выполняться от имени другого пользователя, поэтому сам считается изменяющим сеанс. Кроме того, любой обработчик EXECUTE AS — отдельный или оборачивающий оператор — должен разрешать хотя бы один модифицирующий метод: для имперсонации необходима привилегия IMPERSONATE, которую режим readonly безопасных методов запрещает.
  • TYPE — необязательный. Пока единственный поддерживаемый тип — query.
  • AS — SQL-запрос, который будет выполняться этим обработчиком. Запрос может быть параметризован. При создании или изменении обработчика проверяется синтаксическая корректность запроса, но не выполняется его семантический анализ: например, таблицы, на которые ссылается запрос, могут отсутствовать на момент создания обработчика. Предложение FORMAT и аналогичные секции относятся к запросу, а не ко всему оператору CREATE/ALTER. Для устранения неоднозначности запрос можно заключить в скобки. Запрос INSERT не должен содержать встроенные данные после секции VALUES или FORMAT — при создании или изменении такого обработчика генерируется исключение, поскольку встроенную полезную нагрузку невозможно сохранить в определении обработчика; данные должны передаваться в теле HTTP-запроса (либо вычисляться с помощью INSERT ... SELECT). Запрос к обработчику, запрос которого читает тело, — INSERT, получающий данные из тела, или запрос, использующий параметр _request_body, — должен указывать его длину: на нефрагментированный запрос без заголовка Content-Length возвращается 411 Length Required, поскольку иначе тело считывалось бы до конца потока, а разорванное соединение было бы принято за полный запрос. Каждый метод такого обработчика также должен передавать тело (POST, PUT или DELETE) — создание обработчика с безопасным методом в секции METHODS (например, со стандартным GET) генерирует исключение, поскольку безопасный метод никогда не передаёт тело запроса и запрос молча прочитал бы пустое тело; объявленный GET также обслуживает HEAD, поэтому сочетание безопасных методов и методов с телом сохраняло бы доступность таких вызовов. INSERT ... SELECT не читает тело (его данные поступают из SELECT), поэтому к нему эти требования не применяются — если только его SELECT не читает из табличной функции input, получающей данные из тела запроса. INSERT, читающий тело, должен быть собственным запросом обработчика: EXECUTE AS и PARALLEL WITH выполняют обёрнутые ими операторы без тела запроса, поэтому оборачивание такого запроса в них отклоняется при создании вместо того, чтобы молча отбрасывать каждую загрузку. Запрос, читающий тело, также не должен использовать параметр _request_body: тело запроса существует в единственном экземпляре, и привязка _request_body считывает его до того, как запрос прочитает входные данные, поэтому такой обработчик отклоняется при создании вместо того, чтобы молча терять каждую загрузку — используйте либо собственный ввод из тела запроса, либо _request_body, но не оба варианта. Для обработчиков, не читающих тело, такого требования нет; тело запроса к такому обработчику игнорируется и никогда не добавляется к запросу обработчика. Сохранённый текст запроса повторно разбирается сервером с неограниченной глубиной парсера и числом возвратов при каждой перезагрузке или вызове обработчика, поэтому обработчик, созданный в сеансе с увеличенными max_parser_depth / max_parser_backtracks, остаётся доступным для загрузки и вызова при обычных ограничениях сеанса.

Приоритет

Обработчики, определённые в конфигурации сервера, имеют приоритет над обработчиками, определёнными в SQL. Обработчики, определённые в SQL, сопоставляются в лексикографическом порядке имён.

Параметры

Параметры параметризованных запросов передаются, как и в обработчиках, определённых конфигурацией, из следующих источников:
  • URL-параметров HTTP в строке запроса с использованием соглашения param_<name> (например, ?param_id=42 связывает {id:Type});
  • именованных групп захвата в URL REGEXP (например, URL REGEXP '/users/(?P<id>\d+)' связывает {id:Type});
  • полей формы в теле запроса для обработчика, в запросе которого объявлены параметры: тело application/x-www-form-urlencoded (например, curl -d 'param_id=42') и поля тела multipart/form-data связывают параметры {name:Type} так же, как URL-параметры, для методов с телом POST, PUT и DELETE. Если параметр присутствует и в URL, и в теле запроса, используется значение из URL. Тело, разобранное как форма, потребляется на уровне обработчика: оно не передаётся в запрос как данные INSERT. Если тело используется обработчиком только через _request_body, обработчик получает исходное тело без разбора формы; если обработчик объявляет _request_body наряду с другими параметрами, он получает и то и другое: до разбора тела как формы в _request_body сохраняется копия исходного неразобранного тела (с учётом http_max_request_param_data_size).
Стандартные HTTP-заголовки ClickHouse (например, X-ClickHouse-Database, X-ClickHouse-User, X-ClickHouse-Key) обрабатываются обычным образом при вызове обработчика. Функции currentHandler и currentRequestURL можно использовать для настройки поведения запроса в зависимости от вызванного обработчика и URL запроса.

Управление доступом

Для выполнения CREATE HANDLER, DROP HANDLER и ALTER HANDLER требуются привилегии CREATE HANDLER, DROP HANDLER и ALTER HANDLER соответственно. Для чтения таблицы system.handlers требуется привилегия SHOW HANDLERS. Секреты, которые могут быть встроены в запрос обработчика, маскируются, если пользователю не разрешено просматривать секреты (см. system.handlers). Для вызова обработчика отдельная привилегия не требуется, однако при выполнении запроса привилегии проверяются обычным образом, как и выполняется аутентификация. Чтобы ограничить доступ к определённым запросам, создайте VIEW с SQL SECURITY DEFINER и определите обработчик, выполняющий выборку из этого представления.

Хранилище

Обработчики сохраняются в локальном хранилище или хранилище Keeper, аналогично именованным коллекциям. Хранилище настраивается в разделе query_rules_storage файла конфигурации:
При использовании хранилища Keeper обработчики автоматически синхронизируются на всех репликах, поэтому явное предложение ON CLUSTER избыточно: каждая реплика попытается создать один и тот же обработчик. Включите настройку ignore_on_cluster_for_replicated_handler_queries, чтобы команды CREATE, ALTER и DROP HANDLER игнорировали ON CLUSTER для реплицируемого хранилища, аналогично ignore_on_cluster_for_replicated_named_collections_queries.

ALTER HANDLER

Заменяет обработчик новым. Запрос ALTER может включать только часть секций; например, его можно использовать для изменения только URL или запроса. Неуказанные секции сохраняют прежние значения. PROTOCOL ANY снимает существующее ограничение протокола, снова активируя обработчик на всех конечных точках HTTP.

DROP HANDLER

Удаляет обработчик с указанным именем.

Интроспекция

В таблице system.handlers перечислены все обработчики, определённые в SQL. В таблице system.query_log в столбцах http_handler_name и http_request_url записываются имя обработчика и путь HTTP-запроса (без строки запроса) для каждого запроса.

Пример

Параметризованный обработчик с URL на основе регулярного выражения:
CREATE HANDLER относится к семейству операторов CREATE и связан с ALTER и DROP.
Последнее изменение 27 августа 2026 г.