Para os exemplos deste artigo, você precisará de:
- uma instância do servidor ClickHouse em execução
- ter o
curl instalado. No Ubuntu ou Debian, execute sudo apt install curl ou consulte esta documentação para ver as instruções de instalação.
A interface HTTP permite usar o ClickHouse em qualquer plataforma, com qualquer linguagem de programação, na forma de uma API REST. A interface HTTP é mais limitada do que a interface nativa, mas oferece melhor suporte a linguagens.
Por padrão, o clickhouse-server escuta nas seguintes portas:
- porta 8123 para HTTP
- a porta 8443 para HTTPS pode ser habilitada
Se você fizer uma solicitação GET / sem parâmetros, será retornado um código de resposta 200 junto com a string “Ok.”:
$ curl 'http://localhost:8123/'
Ok.
“Ok.” é o valor padrão definido em http_server_default_response e pode ser alterado, se desejar.
Veja também: Observações sobre códigos de resposta HTTP.
O ClickHouse inclui uma interface web, que pode ser acessada no seguinte endereço:
http://localhost:8123/play
A interface web oferece suporte à exibição do progresso durante a execução da consulta, ao cancelamento de consultas e à transmissão de resultados.
Ela tem um recurso oculto para exibir gráficos e diagramas de pipelines de consulta.
Depois de executar uma consulta com sucesso, aparece um botão de download que permite baixar os resultados da consulta em vários formatos, incluindo CSV, TSV, JSON, JSONLines, Parquet, Markdown ou qualquer formato personalizado compatível com o ClickHouse. A funcionalidade de download usa o cache de consultas para recuperar os resultados com eficiência, sem reexecutar a consulta. Ela fará o download do conjunto completo de resultados mesmo que a UI exiba apenas uma das muitas páginas.
A interface web foi projetada para profissionais como você.
Em scripts de verificação de integridade, use a requisição GET /ping. Este handler sempre retorna “Ok.” (com uma quebra de linha no final). Disponível a partir da versão 18.12.13. Veja também /replicas_status para verificar o atraso da réplica.
$ curl 'http://localhost:8123/ping'
Ok.
$ curl 'http://localhost:8123/replicas_status'
Ok.
Para fazer consultas por HTTP/HTTPS, há três opções:
- enviar a solicitação como um parâmetro
query na URL
- usar o método POST.
- enviar o início da consulta no parâmetro
query e o restante usando POST
O tamanho da URL é limitado a 1 MiB por padrão, mas isso pode ser alterado com a configuração http_max_uri_size.
Se a solicitação for bem-sucedida, você receberá o código de resposta 200 e o resultado no corpo da resposta.
Se ocorrer um erro, você receberá o código de resposta 500 e um texto descritivo do erro no corpo da resposta.
As solicitações que usam GET são ‘somente leitura’. Isso significa que, para consultas que modificam dados, você só pode usar o método POST.
Você pode enviar a própria consulta tanto no corpo da requisição POST quanto como parâmetro na URL. Vamos ver alguns exemplos.
No exemplo abaixo, curl é usado para enviar a consulta SELECT 1. Observe o uso de codificação de URL para o espaço: %20.
curl 'http://localhost:8123/?query=SELECT%201'
Neste exemplo, o wget é usado com os parâmetros -nv (não detalhado) e -O- para exibir o resultado no terminal.
Nesse caso, não é necessário usar codificação de URL para o espaço:
wget -nv -O- 'http://localhost:8123/?query=SELECT 1'
Neste exemplo, enviamos uma requisição HTTP bruta para o netcat:
echo -ne 'GET /?query=SELECT%201 HTTP/1.0\r\n\r\n' | nc localhost 8123
HTTP/1.0 200 OK
X-ClickHouse-Summary: {"read_rows":"1","read_bytes":"1","written_rows":"0","written_bytes":"0","total_rows_to_read":"1","result_rows":"0","result_bytes":"0","elapsed_ns":"4505959","memory_usage":"1111711"}
Date: Tue, 11 Nov 2025 18:16:01 GMT
Connection: Close
Content-Type: text/tab-separated-values; charset=UTF-8
Access-Control-Expose-Headers: X-ClickHouse-Query-Id,X-ClickHouse-Summary,X-ClickHouse-Server-Display-Name,X-ClickHouse-Format,X-ClickHouse-Timezone,X-ClickHouse-Exception-Code,X-ClickHouse-Exception-Tag
X-ClickHouse-Server-Display-Name: MacBook-Pro.local
X-ClickHouse-Query-Id: ec0d8ec6-efc4-4e1d-a14f-b748e01f5294
X-ClickHouse-Format: TabSeparated
X-ClickHouse-Timezone: Europe/London
X-ClickHouse-Exception-Tag: dngjzjnxkvlwkeua
1
Como você pode ver, o comando curl é um tanto inconveniente, já que os espaços precisam ser escapados na URL.
Embora o wget faça esse escape automaticamente, não recomendamos usá-lo porque ele não funciona bem com HTTP 1.1 ao usar keep-alive e Transfer-Encoding: chunked.
$ echo 'SELECT 1' | curl 'http://localhost:8123/' --data-binary @-
1
$ echo 'SELECT 1' | curl 'http://localhost:8123/?query=' --data-binary @-
1
$ echo '1' | curl 'http://localhost:8123/?query=SELECT' --data-binary @-
1
Se parte da consulta for enviada no parâmetro e outra parte no POST, uma quebra de linha será inserida entre essas duas partes de dados.
Por exemplo, isto não funcionará:
$ echo 'ECT 1' | curl 'http://localhost:8123/?query=SEL' --data-binary @-
Code: 59, e.displayText() = DB::Exception: Syntax error: failed at position 0: SEL
ECT 1
, expected One of: SHOW TABLES, SHOW DATABASES, SELECT, INSERT, CREATE, ATTACH, RENAME, DROP, DETACH, USE, SET, OPTIMIZE., e.what() = DB::Exception
Por padrão, os dados são retornados no formato TabSeparated.
A cláusula FORMAT é usada na consulta para especificar qualquer outro formato. Por exemplo:
wget -nv -O- 'http://localhost:8123/?query=SELECT 1, 2, 3 FORMAT JSON'
{
"meta":
[
{
"name": "1",
"type": "UInt8"
},
{
"name": "2",
"type": "UInt8"
},
{
"name": "3",
"type": "UInt8"
}
],
"data":
[
{
"1": 1,
"2": 2,
"3": 3
}
],
"rows": 1,
"statistics":
{
"elapsed": 0.000515,
"rows_read": 1,
"bytes_read": 1
}
}
Você pode usar o parâmetro de URL default_format ou o cabeçalho X-ClickHouse-Format para especificar um formato padrão diferente de TabSeparated.
$ echo 'SELECT 1 FORMAT Pretty' | curl 'http://localhost:8123/?' --data-binary @-
┏━━━┓
┃ 1 ┃
┡━━━┩
│ 1 │
└───┘
Você pode usar o método POST com consultas parametrizadas. Os parâmetros são especificados entre chaves, com o nome e o tipo do parâmetro, como em {name:Type}. Os valores dos parâmetros são enviados com param_name:
$ curl -X POST -F 'query=select {p1:UInt8} + {p2:UInt8}' -F "param_p1=3" -F "param_p2=4" 'http://localhost:8123/'
7
Consultas INSERT via HTTP/HTTPS
O método POST de transmissão de dados é necessário para consultas INSERT. Nesse caso, você pode escrever o início da consulta no parâmetro da URL e usar o POST para enviar os dados a serem inseridos. Os dados a serem inseridos podem ser, por exemplo, um dump do MySQL separado por tabulações. Dessa forma, a consulta INSERT substitui o LOAD DATA LOCAL INFILE do MySQL.
Para criar uma tabela:
$ echo 'CREATE TABLE t (a UInt8) ENGINE = Memory' | curl 'http://localhost:8123/' --data-binary @-
Para usar a consulta INSERT, já conhecida, para inserir dados:
$ echo 'INSERT INTO t VALUES (1),(2),(3)' | curl 'http://localhost:8123/' --data-binary @-
Para enviar os dados separadamente da consulta:
$ echo '(4),(5),(6)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20VALUES' --data-binary @-
É possível especificar qualquer formato de dados. Por exemplo, é possível especificar o formato ‘Values’, o mesmo formato usado ao escrever INSERT INTO t VALUES:
$ echo '(7),(8),(9)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20FORMAT%20Values' --data-binary @-
Para inserir dados de um dump com campos separados por tabulação, especifique o formato correspondente:
$ echo -ne '10\n11\n12\n' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20FORMAT%20TabSeparated' --data-binary @-
Para ler o conteúdo da tabela:
$ curl 'http://localhost:8123/?query=SELECT%20a%20FROM%20t'
7
8
9
10
11
12
1
2
3
4
5
6
Os dados são exibidos em ordem aleatória devido ao processamento paralelo das consultas
Para excluir a tabela:
$ echo 'DROP TABLE t' | curl 'http://localhost:8123/' --data-binary @-
Para solicitações bem-sucedidas que não retornam uma tabela de dados, retorna-se um corpo de resposta vazio.
A compressão pode ser usada para reduzir o tráfego de rede ao transmitir grandes volumes de dados ou para criar dumps já comprimidos.
Ao transmitir dados, você pode usar o formato de compressão interno do ClickHouse. Os dados comprimidos têm um formato não padrão, e você precisa do programa clickhouse-compressor para trabalhar com eles. Ele é instalado por padrão com o pacote clickhouse-client.
Para aumentar a eficiência da inserção de dados, desative a verificação de checksum no lado do servidor com a configuração http_native_compression_disable_checksumming_on_decompress.
Se você especificar compress=1 na URL, o servidor comprimirá os dados enviados para você. Se você especificar decompress=1 na URL, o servidor descomprimirá os dados enviados no método POST.
Você também pode optar por usar a compressão HTTP. O ClickHouse oferece suporte aos seguintes métodos de compressão:
gzip
br
deflate
xz
zstd
lz4
bz2
snappy
Para enviar uma solicitação POST comprimida, adicione o cabeçalho de solicitação Content-Encoding: compression_method.
Para que o ClickHouse comprima a resposta, adicione o cabeçalho Accept-Encoding: compression_method à solicitação.
Você pode configurar o nível de compressão dos dados usando a configuração http_zlib_compression_level para todos os métodos de compressão.
Alguns clientes HTTP podem descomprimir por padrão os dados recebidos do servidor (com gzip e deflate), e você pode receber dados descomprimidos mesmo que use corretamente as configurações de compressão.
Para enviar dados compactados ao servidor:
echo "SELECT 1" | gzip -c | \
curl -sS --data-binary @- -H 'Content-Encoding: gzip' 'http://localhost:8123/'
Para receber o arquivo compactado de dados do servidor:
curl -vsS "http://localhost:8123/?enable_http_compression=1" \
-H 'Accept-Encoding: gzip' --output result.gz -d 'SELECT number FROM system.numbers LIMIT 3'
zcat result.gz
0
1
2
Para receber dados compactados do servidor, use gunzip para descompactá-los:
curl -sS "http://localhost:8123/?enable_http_compression=1" \
-H 'Accept-Encoding: gzip' -d 'SELECT number FROM system.numbers LIMIT 3' | gunzip -
0
1
2
Você pode usar o parâmetro database na URL ou o cabeçalho X-ClickHouse-Database para especificar o banco de dados padrão.
echo 'SELECT number FROM numbers LIMIT 10' | curl 'http://localhost:8123/?database=system' --data-binary @-
0
1
2
3
4
5
6
7
8
9
Por padrão, o banco de dados registrado nas configurações do servidor é usado como banco de dados padrão. Por padrão, esse é o banco de dados chamado default. Como alternativa, você sempre pode especificar o banco de dados usando um ponto antes do nome da tabela.
O nome de usuário e a senha podem ser informados de uma destas três formas:
- Usando autenticação HTTP básica.
Por exemplo:
echo 'SELECT 1' | curl 'http://user:password@localhost:8123/' -d @-
- Nos parâmetros de URL
user e password
Não recomendamos usar esse método, pois o parâmetro pode ser registrado em log por um proxy web e armazenado em cache no navegador
Por exemplo:
echo 'SELECT 1' | curl 'http://localhost:8123/?user=user&password=password' -d @-
- Usando os cabeçalhos ‘X-ClickHouse-User’ e ‘X-ClickHouse-Key’
Por exemplo:
echo 'SELECT 1' | curl -H 'X-ClickHouse-User: user' -H 'X-ClickHouse-Key: password' 'http://localhost:8123/' -d @-
Se o nome de usuário não for especificado, será usado o nome default. Se a senha não for especificada, será usada uma senha vazia.
Você também pode usar os parâmetros de URL para especificar configurações para processar uma única consulta ou perfis inteiros de configurações.
Por exemplo:
http://localhost:8123/?profile=web&max_rows_to_read=1000000000&query=SELECT+1
$ echo 'SELECT number FROM system.numbers LIMIT 10' | curl 'http://localhost:8123/?' --data-binary @-
0
1
2
3
4
5
6
7
8
9
Para mais informações, consulte:
Uso de sessões do ClickHouse no protocolo HTTP
Você também pode usar sessões do ClickHouse no protocolo HTTP. Para isso, é necessário adicionar o parâmetro GET session_id à requisição. Você pode usar qualquer string como ID da sessão.
Por padrão, a sessão é encerrada após 60 segundos de inatividade. Para alterar esse timeout (em segundos), modifique a configuração default_session_timeout na configuração do servidor ou adicione o parâmetro GET session_timeout à requisição.
Para verificar o status da sessão, use o parâmetro session_check=1. Apenas uma consulta por vez pode ser executada em uma única sessão.
Você pode receber informações sobre o progresso de uma consulta nos cabeçalhos de resposta X-ClickHouse-Progress. Para isso, habilite send_progress_in_http_headers.
Abaixo está um exemplo da sequência de cabeçalhos:
X-ClickHouse-Progress: {"read_rows":"261636","read_bytes":"2093088","total_rows_to_read":"1000000","elapsed_ns":"14050417","memory_usage":"22205975"}
X-ClickHouse-Progress: {"read_rows":"654090","read_bytes":"5232720","total_rows_to_read":"1000000","elapsed_ns":"27948667","memory_usage":"83400279"}
X-ClickHouse-Progress: {"read_rows":"1000000","read_bytes":"8000000","total_rows_to_read":"1000000","elapsed_ns":"38002417","memory_usage":"80715679"}
Os possíveis campos de cabeçalho são:
| Campo de cabeçalho | Descrição |
|---|
read_rows | Número de linhas lidas. |
read_bytes | Volume de dados lidos em bytes. |
total_rows_to_read | Número total de linhas a serem lidas. |
written_rows | Número de linhas gravadas. |
written_bytes | Volume de dados gravados em bytes. |
elapsed_ns | Tempo de execução da consulta em nanossegundos. |
memory_usage | Memória em bytes usada pela consulta. (Disponível a partir da v25.11) |
As requisições em execução não param automaticamente se a conexão HTTP for perdida. A análise e a formatação dos dados são realizadas no lado do servidor, e o uso da rede pode ser ineficiente.
Existem os seguintes parâmetros opcionais:
| Parâmetros | Descrição |
|---|
query_id (opcional) | Pode ser informado como o ID da consulta (qualquer string). replace_running_query |
quota_key (opcional) | Pode ser informado como a chave de quota (qualquer string). “Quotas” |
A interface HTTP permite passar dados externos (tabelas temporárias externas) para consulta. Para mais informações, consulte “Dados externos para processamento de consultas”.
A bufferização de resposta pode ser habilitada no lado do servidor. Os seguintes parâmetros de URL são fornecidos para essa finalidade:
buffer_size
wait_end_of_query
As seguintes configurações podem ser usadas:
buffer_size determina o número de bytes do resultado a serem armazenados em buffer na memória do servidor. Se o corpo do resultado for maior que esse limite, o buffer será gravado no canal HTTP, e os dados restantes serão enviados diretamente para o canal HTTP.
Para garantir que toda a resposta seja armazenada em buffer, defina wait_end_of_query=1. Nesse caso, os dados que não forem armazenados na memória serão armazenados em buffer em um arquivo temporário do servidor.
Por exemplo:
curl -sS 'http://localhost:8123/?max_result_bytes=4000000&buffer_size=3000000&wait_end_of_query=1' -d 'SELECT toUInt8(number) FROM system.numbers LIMIT 9000000 FORMAT RowBinary'
Use bufferização para evitar situações em que ocorra um erro no processamento da consulta depois que o código de resposta e os cabeçalhos HTTP forem enviados ao cliente. Nessa situação, uma mensagem de erro é gravada no final do corpo da resposta e, no lado do cliente, o erro só pode ser detectado na etapa de parsing.
Este recurso foi adicionado ao ClickHouse 24.4.
Em cenários específicos, pode ser necessário definir primeiro a role concedida antes de executar a própria instrução.
No entanto, não é possível enviar SET ROLE e a instrução juntos, pois múltiplas instruções não são permitidas:
curl -sS "http://localhost:8123" --data-binary "SET ROLE my_role;SELECT * FROM my_table;"
O comando acima resulta em um erro:
Code: 62. DB::Exception: Syntax error (Multi-statements are not allowed)
Para contornar essa limitação, use o parâmetro de consulta role:
curl -sS "http://localhost:8123?role=my_role" --data-binary "SELECT * FROM my_table;"
Isso equivale a executar SET ROLE my_role antes da instrução.
Além disso, é possível especificar vários parâmetros de consulta role:
curl -sS "http://localhost:8123?role=my_role&role=my_other_role" --data-binary "SELECT * FROM my_table;"
Neste caso, ?role=my_role&role=my_other_role equivale a executar SET ROLE my_role, my_other_role antes da instrução.
Ressalvas sobre códigos de resposta HTTP
Devido às limitações do protocolo HTTP, um código de resposta HTTP 200 não garante que uma consulta tenha sido bem-sucedida.
Veja um exemplo:
curl -v -Ss "http://localhost:8123/?max_block_size=1&query=select+sleepEachRow(0.001),throwIf(number=2)from+numbers(5)"
* Trying 127.0.0.1:8123...
...
< HTTP/1.1 200 OK
...
Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(equals(number, 2) :: 1) -> throwIf(equals(number, 2))
O motivo desse comportamento é a própria natureza do protocolo HTTP. O cabeçalho HTTP é enviado primeiro com o código HTTP 200, seguido pelo corpo HTTP, e então o erro é injetado no corpo como texto simples.
Esse comportamento é independente do formato usado, seja Native, TSV ou JSON; a mensagem de erro sempre aparecerá no meio do fluxo de resposta.
Você pode mitigar esse problema habilitando wait_end_of_query=1 (Buffering de resposta). Nesse caso, o envio do cabeçalho HTTP é adiado até que toda a consulta seja concluída. No entanto, isso não resolve completamente o problema, porque o resultado ainda precisa caber em http_response_buffer_size, e outras configurações, como send_progress_in_http_headers, podem interferir no atraso do cabeçalho.
A única forma de capturar todos os erros é analisar o corpo HTTP antes de fazer o parsing usando o formato necessário.
Essas exceções no ClickHouse têm um formato consistente, como mostrado abaixo, independentemente do formato usado (por exemplo, Native, TSV, JSON etc.) quando http_write_exception_in_output_format=0 (padrão). Isso facilita o parsing e a extração de mensagens de erro no lado do cliente.
\r\n
__exception__\r\n
<TAG>\r\n
<error message>\r\n
<message_length> <TAG>\r\n
__exception__\r\n
Onde <TAG> é uma tag aleatória de 16 bytes, a mesma tag enviada no header de resposta X-ClickHouse-Exception-Tag.
A <error message> é a mensagem real da exceção (o comprimento exato pode ser encontrado em <message_length>). Todo o bloco de exceção descrito acima pode ter até 16 KiB.
Aqui está um exemplo no formato JSON
$ curl -v -Ss "http://localhost:8123/?max_block_size=1&query=select+sleepEachRow(0.001),throwIf(number=2)from+numbers(5)+FORMAT+JSON"
...
{
"meta":
[
{
"name": "sleepEachRow(0.001)",
"type": "UInt8"
},
{
"name": "throwIf(equals(number, 2))",
"type": "UInt8"
}
],
"data":
[
{
"sleepEachRow(0.001)": 0,
"throwIf(equals(number, 2))": 0
},
{
"sleepEachRow(0.001)": 0,
"throwIf(equals(number, 2))": 0
}
__exception__
dmrdfnujjqvszhav
Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(equals(__table1.number, 2_UInt8) :: 1) -> throwIf(equals(__table1.number, 2_UInt8)) UInt8 : 0'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 25.11.1.1)
262 dmrdfnujjqvszhav
__exception__
Veja um exemplo semelhante, mas no formato CSV
$ curl -v -Ss "http://localhost:8123/?max_block_size=1&query=select+sleepEachRow(0.001),throwIf(number=2)from+numbers(5)+FORMAT+CSV"
...
<
0,0
0,0
__exception__
rumfyutuqkncbgau
Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(equals(__table1.number, 2_UInt8) :: 1) -> throwIf(equals(__table1.number, 2_UInt8)) UInt8 : 0'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 25.11.1.1)
262 rumfyutuqkncbgau
__exception__
Você pode criar uma consulta com parâmetros e informar os valores deles por meio dos parâmetros correspondentes da solicitação HTTP. Para mais informações, consulte Consultas com parâmetros para CLI.
$ curl -sS "<address>?param_id=2¶m_phrase=test" -d "SELECT * FROM table WHERE int_column = {id:UInt8} and string_column = {phrase:String}"
Tabulações em parâmetros de URL
Os parâmetros de consulta são interpretados a partir do formato “escaped”. Isso traz alguns benefícios, como a possibilidade de interpretar valores nulos sem ambiguidade como \N. Isso significa que o caractere de tabulação deve ser codificado como \t (ou \ seguido de uma tabulação). Por exemplo, o trecho a seguir contém uma tabulação real entre abc e 123, e a string de entrada é dividida em dois valores:
curl -sS "http://localhost:8123" -d "SELECT splitByChar('\t', 'abc 123')"
No entanto, se você tentar codificar um caractere de tabulação real usando %09 em um parâmetro de URL, ele não será interpretado corretamente:
curl -sS "http://localhost:8123?param_arg1=abc%09123" -d "SELECT splitByChar('\t', {arg1:String})"
Code: 457. DB::Exception: Value abc 123 cannot be parsed as String for query parameter 'arg1' because it isn't parsed completely: only 3 of 7 bytes was parsed: abc. (BAD_QUERY_PARAMETER) (version 23.4.1.869 (official build))
Se estiver usando parâmetros de URL, você precisará codificar \t como %5C%09. Por exemplo:
curl -sS "http://localhost:8123?param_arg1=abc%5C%09123" -d "SELECT splitByChar('\t', {arg1:String})"
Interface HTTP predefinida
O ClickHouse suporta consultas específicas por meio da interface HTTP. Por exemplo, você pode gravar dados em uma tabela da seguinte forma:
$ echo '(4),(5),(6)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20VALUES' --data-binary @-
O ClickHouse também oferece suporte a uma Interface HTTP predefinida, o que pode facilitar a integração com ferramentas de terceiros, como o Prometheus exporter. Vamos ver um exemplo.
Antes de mais nada, adicione esta seção ao arquivo de configuração do servidor.
http_handlers é configurado para conter várias rule. O ClickHouse faz a correspondência entre as requisições HTTP recebidas e o tipo predefinido em rule, e a primeira regra correspondente executa o handler. Em seguida, o ClickHouse executa a consulta predefinida correspondente se a correspondência for bem-sucedida.
<http_handlers>
<rule>
<url>/predefined_query</url>
<methods>POST,GET</methods>
<handler>
<type>predefined_query_handler</type>
<query>SELECT * FROM system.metrics LIMIT 5 FORMAT Template SETTINGS format_template_resultset = 'prometheus_template_output_format_resultset', format_template_row = 'prometheus_template_output_format_row', format_template_rows_between_delimiter = '\n'</query>
</handler>
</rule>
<rule>...</rule>
<rule>...</rule>
</http_handlers>
Agora você pode fazer uma solicitação diretamente à URL para obter dados no formato Prometheus:
$ curl -v 'http://localhost:8123/predefined_query'
* Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /predefined_query HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 28 Apr 2020 08:52:56 GMT
< Connection: Keep-Alive
< Content-Type: text/plain; charset=UTF-8
< X-ClickHouse-Server-Display-Name: i-mloy5trc
< Transfer-Encoding: chunked
< X-ClickHouse-Query-Id: 96fe0052-01e6-43ce-b12a-6b7370de6e8a
< X-ClickHouse-Format: Template
< X-ClickHouse-Timezone: Asia/Shanghai
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
# HELP "Query" "Número de consultas em execução"
# TYPE "Query" counter
"Query" 1
# HELP "Merge" "Número de merges em segundo plano em execução"
# TYPE "Merge" counter
"Merge" 0
# HELP "PartMutation" "Número de mutações (ALTER DELETE/UPDATE)"
# TYPE "PartMutation" counter
"PartMutation" 0
# HELP "ReplicatedFetch" "Número de partes de dados sendo obtidas da réplica"
# TYPE "ReplicatedFetch" counter
"ReplicatedFetch" 0
# HELP "ReplicatedSend" "Número de partes de dados sendo enviadas para as réplicas"
# TYPE "ReplicatedSend" counter
"ReplicatedSend" 0
* Connection #0 to host localhost left intact
* Connection #0 to host localhost left intact
As opções de configuração de http_handlers funcionam da seguinte forma.
rule pode configurar os seguintes parâmetros:
method
headers
url
full_url
handler
Cada um deles é explicado abaixo:
-
method é responsável por corresponder à parte do método da requisição HTTP. method está totalmente em conformidade com a definição de [method]
(https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) no protocolo HTTP. É uma configuração opcional. Se não estiver definido no
arquivo de configuração, não fará correspondência com a parte do método da requisição HTTP.
-
url é responsável por corresponder à parte da URL (path e query string) da requisição HTTP.
Se url tiver o prefixo regex:, serão esperadas expressões regulares RE2.
É uma configuração opcional. Se não estiver definido no arquivo de configuração, não fará correspondência com a parte da URL da requisição HTTP.
-
full_url é igual a url, mas inclui a URL completa, isto é, schema://host:port/path?query_string.
Observe que o ClickHouse não oferece suporte a “virtual hosts”, portanto host é um endereço IP (e não o valor do cabeçalho Host).
-
empty_query_string - garante que não haja query string (?query_string) na requisição
-
headers são responsáveis por corresponder à parte dos cabeçalhos da requisição HTTP. É compatível com expressões regulares RE2. É uma configuração opcional
. Se não estiver definido no arquivo de configuração, não fará correspondência com a parte dos cabeçalhos da requisição HTTP.
-
handler contém a parte principal do processamento.
Ele pode ter o seguinte type:
E os seguintes parâmetros:
query — use com o tipo predefined_query_handler; executa a consulta quando o handler é chamado.
query_param_name — use com o tipo dynamic_query_handler; extrai e executa o valor correspondente a query_param_name nos parâmetros da requisição HTTP.
status — use com o tipo static, código de status da resposta.
content_type — use com qualquer tipo, content-type da resposta.
http_response_headers — use com qualquer tipo, map dos cabeçalhos da resposta. Também pode ser usado para definir o tipo de conteúdo.
response_content — use com o tipo static, conteúdo da resposta enviado ao cliente; ao usar o prefixo ‘file://’ ou ‘config://’, o conteúdo é obtido do arquivo ou da configuração e enviado ao cliente.
user - usuário com o qual executar a consulta (o usuário padrão é default).
Observação, você não precisa especificar a senha desse usuário.
Os métodos de configuração para diferentes types são discutidos a seguir.
predefined_query_handler oferece suporte à definição de valores de Settings e query_params. Você pode configurar query para o tipo predefined_query_handler.
O valor de query é uma consulta predefinida de predefined_query_handler, executada pelo ClickHouse quando uma requisição HTTP corresponde a ela, e o resultado da consulta é retornado. Essa configuração é obrigatória.
O exemplo a seguir define os valores das configurações max_threads e max_final_threads e, em seguida, consulta a tabela de sistema para verificar se essas configurações foram definidas com sucesso.
Para manter os handlers padrão, como query, play e ping, adicione a regra <defaults/>.
Por exemplo:
<http_handlers>
<rule>
<url><![CDATA[regex:/query_param_with_url/(?P<name_1>[^/]+)]]></url>
<methods>GET</methods>
<headers>
<XXX>TEST_HEADER_VALUE</XXX>
<PARAMS_XXX><![CDATA[regex:(?P<name_2>[^/]+)]]></PARAMS_XXX>
</headers>
<handler>
<type>predefined_query_handler</type>
<query>
SELECT name, value FROM system.settings
WHERE name IN ({name_1:String}, {name_2:String})
</query>
</handler>
</rule>
<defaults/>
</http_handlers>
curl -H 'XXX:TEST_HEADER_VALUE' -H 'PARAMS_XXX:max_final_threads' 'http://localhost:8123/query_param_with_url/max_threads?max_threads=1&max_final_threads=2'
max_final_threads 2
max_threads 1
Parâmetro virtual _request_body
Além dos parâmetros de URL, cabeçalhos e parâmetros de consulta, predefined_query_handler oferece suporte a um parâmetro virtual especial, _request_body.
Ele contém o corpo bruto da requisição HTTP como uma string.
Isso permite criar APIs REST flexíveis que podem aceitar formatos de dados arbitrários e processá-los nas suas consultas.
Por exemplo, você pode usar _request_body para implementar um endpoint REST que aceita dados JSON em uma requisição POST e os insere em uma tabela:
<http_handlers>
<rule>
<methods>POST</methods>
<url>/api/events</url>
<handler>
<type>predefined_query_handler</type>
<query>
INSERT INTO events (id, data)
SELECT {id:UInt32}, {_request_body:String}
</query>
</handler>
</rule>
<defaults/>
</http_handlers>
Em seguida, você pode enviar dados para este endpoint:
curl -X POST 'http://localhost:8123/api/events?id=123' \
-H 'Content-Type: application/json' \
-d '{"user": "john", "action": "login", "timestamp": "2024-01-01T10:00:00Z"}'
Em um predefined_query_handler, apenas uma consulta é compatível.
Em dynamic_query_handler, a consulta é escrita como um parâmetro da requisição HTTP. A diferença é que, em predefined_query_handler, a consulta é escrita no arquivo de configuração. query_param_name pode ser configurado em dynamic_query_handler.
O ClickHouse extrai e executa o valor correspondente a query_param_name na URL da requisição HTTP. O valor padrão de query_param_name é /query. Essa é uma configuração opcional. Se não houver definição no arquivo de configuração, o parâmetro não será passado.
Para testar essa funcionalidade, o exemplo a seguir define os valores de max_threads e max_final_threads e consulta se as configurações foram definidas com sucesso.
Exemplo:
<http_handlers>
<rule>
<headers>
<XXX>TEST_HEADER_VALUE_DYNAMIC</XXX> </headers>
<handler>
<type>dynamic_query_handler</type>
<query_param_name>query_param</query_param_name>
</handler>
</rule>
<defaults/>
</http_handlers>
curl -H 'XXX:TEST_HEADER_VALUE_DYNAMIC' 'http://localhost:8123/own?max_threads=1&max_final_threads=2¶m_name_1=max_threads¶m_name_2=max_final_threads&query_param=SELECT%20name,value%20FROM%20system.settings%20where%20name%20=%20%7Bname_1:String%7D%20OR%20name%20=%20%7Bname_2:String%7D'
max_threads 1
max_final_threads 2
static pode retornar content_type, status e response_content. response_content pode retornar o conteúdo especificado.
Por exemplo, para retornar a mensagem “Say Hi!”:
<http_handlers>
<rule>
<methods>GET</methods>
<headers><XXX>xxx</XXX></headers>
<url>/hi</url>
<handler>
<type>static</type>
<status>402</status>
<content_type>text/html; charset=UTF-8</content_type>
<http_response_headers>
<Content-Language>en</Content-Language>
<X-My-Custom-Header>43</X-My-Custom-Header>
</http_response_headers>
<response_content>Say Hi!</response_content>
</handler>
</rule>
<defaults/>
</http_handlers>
http_response_headers pode ser usado para definir o tipo de conteúdo em vez de content_type.
<http_handlers>
<rule>
<methods>GET</methods>
<headers><XXX>xxx</XXX></headers>
<url>/hi</url>
<handler>
<type>static</type>
<status>402</status>
#begin-highlight
<http_response_headers>
<Content-Type>text/html; charset=UTF-8</Content-Type>
<Content-Language>en</Content-Language>
<X-My-Custom-Header>43</X-My-Custom-Header>
</http_response_headers>
#end-highlight
<response_content>Say Hi!</response_content>
</handler>
</rule>
<defaults/>
</http_handlers>
curl -vv -H 'XXX:xxx' 'http://localhost:8123/hi'
* Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /hi HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 402 Payment Required
< Date: Wed, 29 Apr 2020 03:51:26 GMT
< Connection: Keep-Alive
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
* Connection #0 to host localhost left intact
Say Hi!%
Encontre o conteúdo da configuração enviada ao cliente.
<get_config_static_handler><![CDATA[<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>]]></get_config_static_handler>
<http_handlers>
<rule>
<methods>GET</methods>
<headers><XXX>xxx</XXX></headers>
<url>/get_config_static_handler</url>
<handler>
<type>static</type>
<response_content>config://get_config_static_handler</response_content>
</handler>
</rule>
</http_handlers>
$ curl -v -H 'XXX:xxx' 'http://localhost:8123/get_config_static_handler'
* Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /get_config_static_handler HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 200 OK
< Date: Wed, 29 Apr 2020 04:01:24 GMT
< Connection: Keep-Alive
< Content-Type: text/plain; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
* Connection #0 to host localhost left intact
<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>%
Para encontrar o conteúdo do arquivo enviado ao cliente:
<http_handlers>
<rule>
<methods>GET</methods>
<headers><XXX>xxx</XXX></headers>
<url>/get_absolute_path_static_handler</url>
<handler>
<type>static</type>
<content_type>text/html; charset=UTF-8</content_type>
<http_response_headers>
<ETag>737060cd8c284d8af7ad3082f209582d</ETag>
</http_response_headers>
<response_content>file:///absolute_path_file.html</response_content>
</handler>
</rule>
<rule>
<methods>GET</methods>
<headers><XXX>xxx</XXX></headers>
<url>/get_relative_path_static_handler</url>
<handler>
<type>static</type>
<content_type>text/html; charset=UTF-8</content_type>
<http_response_headers>
<ETag>737060cd8c284d8af7ad3082f209582d</ETag>
</http_response_headers>
<response_content>file://./relative_path_file.html</response_content>
</handler>
</rule>
</http_handlers>
$ user_files_path='/var/lib/clickhouse/user_files'
$ sudo echo "<html><body>Relative Path File</body></html>" > $user_files_path/relative_path_file.html
$ sudo echo "<html><body>Absolute Path File</body></html>" > $user_files_path/absolute_path_file.html
$ curl -vv -H 'XXX:xxx' 'http://localhost:8123/get_absolute_path_static_handler'
* Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /get_absolute_path_static_handler HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 200 OK
< Date: Wed, 29 Apr 2020 04:18:16 GMT
< Connection: Keep-Alive
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
<html><body>Absolute Path File</body></html>
* Connection #0 to host localhost left intact
$ curl -vv -H 'XXX:xxx' 'http://localhost:8123/get_relative_path_static_handler'
* Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /get_relative_path_static_handler HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 200 OK
< Date: Wed, 29 Apr 2020 04:18:31 GMT
< Connection: Keep-Alive
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
<html><body>Relative Path File</body></html>
* Connection #0 to host localhost left intact
redirect fará um redirecionamento 302 para location
Por exemplo, veja como adicionar automaticamente set user ao play do ClickHouse:
<clickhouse>
<http_handlers>
<rule>
<methods>GET</methods>
<url>/play</url>
<handler>
<type>redirect</type>
<location>/play?user=play</location>
</handler>
</rule>
</http_handlers>
</clickhouse>
O ClickHouse permite configurar cabeçalhos de resposta HTTP personalizados que podem ser aplicados a qualquer tipo de handler configurável. Esses cabeçalhos podem ser definidos usando a configuração http_response_headers, que aceita pares chave-valor que representam nomes de cabeçalhos e seus respectivos valores. Esse recurso é especialmente útil para implementar cabeçalhos de segurança personalizados, políticas de CORS ou quaisquer outros requisitos de cabeçalhos HTTP em toda a interface HTTP do ClickHouse.
Por exemplo, você pode configurar cabeçalhos para:
- Endpoints de consulta regulares
- UI da Web
- Verificação de integridade.
Também é possível especificar common_http_response_headers. Eles serão aplicados a todos os handlers HTTP definidos na configuração.
Os cabeçalhos serão incluídos na resposta HTTP de cada handler configurado.
No exemplo abaixo, toda resposta do servidor conterá dois cabeçalhos personalizados: X-My-Common-Header e X-My-Custom-Header.
<clickhouse>
<http_handlers>
<common_http_response_headers>
<X-My-Common-Header>Common header</X-My-Common-Header>
</common_http_response_headers>
<rule>
<methods>GET</methods>
<url>/ping</url>
<handler>
<type>ping</type>
<http_response_headers>
<X-My-Custom-Header>Custom indeed</X-My-Custom-Header>
</http_response_headers>
</handler>
</rule>
</http_handlers>
</clickhouse>
Resposta JSON/XML válida em caso de exceção durante HTTP streaming
Durante a execução da consulta por HTTP, pode ocorrer uma exceção quando parte dos dados já tiver sido enviada. Normalmente, a exceção é enviada ao cliente em texto simples.
Mesmo que tenha sido usado um formato de dados específico para a saída, ela pode acabar se tornando inválida em relação ao formato especificado.
Para evitar isso, você pode usar a configuração http_write_exception_in_output_format (desabilitada por padrão), que faz com que o ClickHouse grave a exceção no formato especificado (atualmente compatível com os formatos XML e JSON*).
Exemplos:
$ curl 'http://localhost:8123/?query=SELECT+number,+throwIf(number>3)+from+system.numbers+format+JSON+settings+max_block_size=1&http_write_exception_in_output_format=1'
{
"meta":
[
{
"name": "number",
"type": "UInt64"
},
{
"name": "throwIf(greater(number, 2))",
"type": "UInt8"
}
],
"data":
[
{
"number": "0",
"throwIf(greater(number, 2))": 0
},
{
"number": "1",
"throwIf(greater(number, 2))": 0
},
{
"number": "2",
"throwIf(greater(number, 2))": 0
}
],
"rows": 3,
"exception": "Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(greater(number, 2) :: 2) -> throwIf(greater(number, 2)) UInt8 : 1'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 23.8.1.1)"
}
$ curl 'http://localhost:8123/?query=SELECT+number,+throwIf(number>2)+from+system.numbers+format+XML+settings+max_block_size=1&http_write_exception_in_output_format=1'
<?xml version='1.0' encoding='UTF-8' ?>
<result>
<meta>
<columns>
<column>
<name>number</name>
<type>UInt64</type>
</column>
<column>
<name>throwIf(greater(number, 2))</name>
<type>UInt8</type>
</column>
</columns>
</meta>
<data>
<row>
<number>0</number>
<field>0</field>
</row>
<row>
<number>1</number>
<field>0</field>
</row>
<row>
<number>2</number>
<field>0</field>
</row>
</data>
<rows>3</rows>
<exception>Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(greater(number, 2) :: 2) -> throwIf(greater(number, 2)) UInt8 : 1'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 23.8.1.1)</exception>
</result>