Skip to main content
Crea un handler HTTP personalizado definido mediante SQL, sin editar el archivo de configuración del servidor. Los handlers definidos mediante SQL son una alternativa a los handlers de la interfaz HTTP.

Sintaxis

Crea un handler con el name especificado. El nombre se utiliza para gestionar handlers mediante consultas SQL, en mensajes de diagnóstico y para ordenarlos.

Cláusulas

  • PROTOCOL — opcional. Si se especifica un nombre de protocolo, el controlador solo está activo para el protocolo componible indicado. De lo contrario, el controlador está activo en todos los endpoints HTTP: los puertos integrados http/https y todos los listeners de protocolo componible de tipo HTTP. PROTOCOL ANY selecciona explícitamente este comportamiento predeterminado; en ALTER HANDLER, elimina una restricción de protocolo establecida previamente. Se puede hacer referencia a un protocolo llamado literalmente any mediante comillas invertidas: PROTOCOL `any` .
  • URL — obligatorio. Puede ser una URL exacta, un URL PREFIX o un URL REGEXP. Para las URL exactas y los prefijos, se comprueba si hay ambigüedad al crear o alterar el controlador y se genera una excepción si la hay. En el caso de las expresiones regulares, no se puede comprobar la ambigüedad. La URL se compara sin la cadena de consulta ? ni el identificador de fragmento #. Un URL PREFIX se compara como una ruta base, en un límite de segmento de ruta — con la misma semántica que la regla url_prefix de los controladores definidos mediante configuración: URL PREFIX '/api/v1' coincide con /api/v1, /api/v1/ y /api/v1/write, pero no con /api/v1beta. La / final del prefijo se ignora, por lo que '/api/v1/' y '/api/v1' se comportan igual.
  • METHODS — opcional. La lista de métodos HTTP permitidos. De forma predeterminada, solo se permite GET. Los métodos compatibles son GET, POST, PUT y DELETE. Los métodos que modifican datos, POST, PUT y DELETE, pueden ejecutar consultas modificadoras; los métodos seguros, como GET y HEAD, siempre se ejecutan en modo readonly. Por lo tanto, un controlador cuya consulta modifica datos (por ejemplo, INSERT o DDL) debe permitir al menos un método de modificación; crear un controlador de este tipo únicamente con métodos de solo lectura (por ejemplo, el GET predeterminado) genera una excepción. Las consultas cuyos efectos secundarios persisten en modo readonly constituyen un caso especial: BACKUP y RESTORE tienen efectos secundarios duraderos; las sentencias que modifican la sesión, SET, SET ROLE, USE, BEGIN TRANSACTION, COMMIT, ROLLBACK y SET TRANSACTION SNAPSHOT, cambian el estado de la sesión o de la transacción, que persiste entre solicitudes cuando se usa session_id; y CREATE TEMPORARY TABLE / CREATE TEMPORARY VIEW crean un objeto que existe en la sesión. Sin embargo, el modo readonly de los métodos seguros no bloquea ninguna de ellas. Las mutaciones de una tabla temporal existente tampoco quedan bloqueadas por el modo readonly, por lo que las consultas que puedan tener una tabla de este tipo como destino se tratan del mismo modo: un INSERT cuya tabla de destino no está calificada con una base de datos (un nombre no calificado puede resolverse como una tabla temporal de sesión), un DROP TEMPORARY TABLE, un DROP TABLE / TRUNCATE TABLE de una tabla no calificada con una base de datos y un ALTER de una tabla no calificada con una base de datos (ALTER TEMPORARY TABLE es la misma sentencia). Un destino calificado con una base de datos nunca puede ser una tabla temporal, por lo que dichas consultas no están sujetas a esta regla. HTTP exige que los métodos seguros no tengan efectos secundarios (un controlador declarado para GET también se sirve para HEAD, donde se suprime el cuerpo de la respuesta y el efecto sería invisible). Por lo tanto, un controlador que ejecute una consulta de este tipo debe enumerar únicamente métodos de modificación; crearlo o modificarlo para incluir un método seguro genera una excepción. Se inspeccionan las sentencias compuestas: para statement1 PARALLEL WITH statement2 ... y EXECUTE AS <user> <statement>, las reglas anteriores se aplican a las sentencias encapsuladas, ya que son las que se ejecutan (cada una con una copia del contexto del controlador, que conserva el modo readonly). Un EXECUTE AS <user> sin sentencia hace que toda la sesión se ejecute como otro usuario, por lo que cuenta como una modificación de la sesión por sí mismo. Además, cualquier controlador EXECUTE AS, ya sea sin sentencia o encapsulando una sentencia, debe permitir al menos un método de modificación: la suplantación requiere el privilegio IMPERSONATE, que el modo readonly de los métodos seguros deniega.
  • TYPE — opcional. Por ahora, el único tipo compatible es query.
  • AS — la consulta SQL que invocará este handler. La consulta puede parametrizarse. Durante la creación o modificación del handler, se analiza la corrección sintáctica de la consulta, pero no su semántica; por ejemplo, las tablas a las que hace referencia pueden no existir en el momento de crear el handler. Las cláusulas FORMAT y similares pertenecen a la consulta, no a toda la sentencia CREATE/ALTER. La consulta puede incluirse entre paréntesis para evitar ambigüedades. Una consulta INSERT no debe contener datos en línea después de la cláusula VALUES o FORMAT: crear o modificar un handler de este tipo genera una excepción, ya que la carga útil en línea no puede conservarse en la definición del handler; los datos deben proporcionarse en el cuerpo HTTP (o calcularse mediante un INSERT ... SELECT). Una solicitud a un handler cuya consulta lee el cuerpo —un INSERT que toma sus datos del cuerpo o una consulta que utiliza el parámetro _request_body— debe declarar su longitud: una solicitud no fragmentada sin un encabezado Content-Length recibe la respuesta 411 Length Required, ya que, de lo contrario, el cuerpo se leería hasta el final del flujo y una conexión interrumpida se aceptaría como una solicitud completa. Todos los métodos de dicho handler también deben incluir un cuerpo (POST, PUT o DELETE): crearlo con un método seguro en la cláusula METHODS (por ejemplo, el GET predeterminado) genera una excepción, porque un método seguro nunca proporciona un cuerpo de solicitud y la consulta leería silenciosamente uno vacío; un GET declarado también se sirve para HEAD, por lo que mezclar métodos seguros y métodos con cuerpo mantendría accesibles esas invocaciones. Un INSERT ... SELECT no lee el cuerpo (sus datos proceden del SELECT), por lo que no está sujeto a estos requisitos, salvo que su SELECT lea de la función de tabla input, que recibe datos del cuerpo de la solicitud. Un INSERT que lee el cuerpo debe ser la propia consulta del handler: EXECUTE AS y PARALLEL WITH ejecutan las sentencias que contienen sin el cuerpo de la solicitud, por lo que envolver uno en ellas se rechaza al crearlo en lugar de descartar silenciosamente cada carga. Una consulta que lee el cuerpo tampoco debe utilizar el parámetro _request_body: hay un único cuerpo de solicitud, y la vinculación de _request_body lo consume antes de que la consulta lea sus datos de entrada, por lo que dicho handler se rechaza al crearlo en lugar de perder silenciosamente cada carga; utilice la propia entrada del cuerpo de la consulta o _request_body, pero no ambos. Los handlers que no leen el cuerpo no tienen este requisito; el cuerpo de una solicitud a dicho handler se ignora y nunca se añade a la consulta del handler. El texto de consulta almacenado vuelve a analizarse en el servidor con profundidad del analizador y retrocesos ilimitados cada vez que se recarga o invoca el handler, por lo que un handler creado en una sesión con max_parser_depth / max_parser_backtracks aumentados sigue pudiendo cargarse e invocarse con los límites habituales de sesión.

Prioridad

Los handlers definidos en la configuración del servidor tienen prioridad sobre los definidos en SQL. Los handlers definidos en SQL se comparan en orden lexicográfico según sus nombres.

Parámetros

Los parámetros de consulta para consultas parametrizadas se proporcionan, al igual que en los handlers definidos mediante configuración, a partir de:
  • parámetros de URL HTTP en la cadena de consulta, mediante la convención param_<name> (por ejemplo, ?param_id=42 vincula {id:Type});
  • grupos de captura con nombre en una URL REGEXP (por ejemplo, URL REGEXP '/users/(?P<id>\d+)' vincula {id:Type});
  • campos de formulario del cuerpo de la solicitud, para un handler cuya consulta declara parámetros: un cuerpo application/x-www-form-urlencoded (por ejemplo, curl -d 'param_id=42') y los campos de un cuerpo multipart/form-data vinculan parámetros {name:Type} de la misma forma que los parámetros de URL en los métodos con cuerpo POST, PUT y DELETE. Un parámetro presente tanto en la URL como en el cuerpo toma su valor de la URL. Un cuerpo analizado como formulario es consumido por la capa de handlers: no se pasa a la consulta como datos de INSERT. Un handler cuyo único uso del cuerpo es _request_body recibe el cuerpo sin procesar en lugar de analizarlo como formulario; un handler que declara _request_body junto con otros parámetros recibe ambos: se conserva una copia del cuerpo sin procesar en _request_body (sujeta a http_max_request_param_data_size) antes de analizar el cuerpo como formulario.
Los encabezados HTTP estándar de ClickHouse (como X-ClickHouse-Database, X-ClickHouse-User y X-ClickHouse-Key) se respetan como de costumbre al invocar un handler. Las funciones currentHandler y currentRequestURL se pueden utilizar para personalizar el comportamiento de la consulta según el handler invocado y la URL de la solicitud.

Control de acceso

CREATE HANDLER, DROP HANDLER y ALTER HANDLER requieren los privilegios CREATE HANDLER, DROP HANDLER y ALTER HANDLER, respectivamente. La lectura de la tabla system.handlers requiere el privilegio SHOW HANDLERS. Los secretos que puedan estar incluidos en la consulta de un handler se ocultan allí, a menos que el usuario también tenga permiso para ver secretos (consulte system.handlers). La invocación de un handler no requiere ningún privilegio independiente, pero los privilegios se comprueban como de costumbre durante la invocación de la consulta y la autenticación funciona de la forma habitual. Para encapsular el acceso a determinadas consultas, cree una VIEW con SQL SECURITY DEFINER y defina un handler que seleccione de esa vista.

Almacenamiento

Los handler se guardan en un almacenamiento local o de Keeper, de forma similar a las colecciones con nombre, configurado en la sección query_rules_storage del archivo de configuración:
Con el almacenamiento Keeper, los handlers se sincronizan automáticamente en todas las réplicas, por lo que una cláusula ON CLUSTER explícita es redundante y haría que cada réplica intentara crear el mismo handler. Habilite la configuración ignore_on_cluster_for_replicated_handler_queries para que CREATE, ALTER y DROP HANDLER ignoren ON CLUSTER cuando el almacenamiento sea replicado, al igual que ignore_on_cluster_for_replicated_named_collections_queries.

ALTER HANDLER

Reemplaza el handler por uno nuevo. La consulta ALTER solo puede incluir un subconjunto de cláusulas; por ejemplo, puede utilizarse únicamente para cambiar la URL o la consulta. Las cláusulas no especificadas conservan sus valores anteriores. PROTOCOL ANY elimina una restricción de protocolo existente, lo que vuelve a activar el handler en todos los endpoints HTTP.

DROP HANDLER

Elimina el handler con el nombre especificado.

Introspección

La tabla system.handlers enumera todos los handlers definidos en SQL. La tabla system.query_log registra, para cada consulta, el nombre del handler y la ruta de la solicitud HTTP (sin la cadena de consulta) en las columnas http_handler_name y http_request_url.

Ejemplo

Un handler parametrizado con una URL con formato Regexp:
CREATE HANDLER forma parte de la familia de sentencias CREATE y se relaciona con ALTER y DROP.
Última modificación el 27 de agosto de 2026