Предварительные требования
Для примеров в этой статье вам понадобятся:
- запущенный экземпляр сервера ClickHouse
- установленный
curl. В Ubuntu или Debian выполните sudo apt install curl или обратитесь к этой документации за инструкциями по установке.
HTTP-интерфейс позволяет использовать ClickHouse на любой платформе из любого языка программирования в формате REST API. HTTP-интерфейс более ограничен, чем native interface, но обеспечивает лучшую поддержку языков программирования.
По умолчанию clickhouse-server прослушивает следующие порты:
- порт 8123 для HTTP
- можно включить порт 8443 для HTTPS
Если выполнить запрос GET / без каких-либо параметров, будет возвращён код ответа 200 вместе со строкой “Ok.”:
$ curl 'http://localhost:8123/'
Ok.
“Ok.” — это значение по умолчанию, заданное в http_server_default_response; при необходимости его можно изменить.
См. также: особенности кодов HTTP-ответов.
В ClickHouse есть веб-интерфейс, доступный по следующему адресу:
http://localhost:8123/play
Веб-интерфейс поддерживает отображение прогресса во время выполнения запроса, отмену запроса и потоковую передачу результатов.
В нём есть скрытая возможность для отображения диаграмм и графиков конвейеров выполнения запросов.
После успешного выполнения запроса появляется кнопка загрузки, позволяющая скачать результаты запроса в различных форматах, включая CSV, TSV, JSON, JSONLines, Parquet, Markdown или любой другой пользовательский формат, поддерживаемый ClickHouse. Возможность загрузки использует кэш запросов, чтобы эффективно получать результаты без повторного выполнения запроса. Будет загружен полный результирующий набор, даже если в интерфейсе отображалась только одна страница из многих.
Веб-интерфейс создан для таких профессионалов, как вы.
В скриптах проверки работоспособности используйте запрос GET /ping. Этот обработчик всегда возвращает “Ok.” (с символом перевода строки в конце). Доступно начиная с версии 18.12.13. См. также /replicas_status, чтобы проверить задержку реплики.
$ curl 'http://localhost:8123/ping'
Ok.
$ curl 'http://localhost:8123/replicas_status'
Ok.
Выполнение запросов по HTTP/HTTPS
Для выполнения запросов по HTTP/HTTPS есть три варианта:
- передать запрос в параметре URL ‘query’
- использовать метод POST.
- Передать начало запроса в параметре ‘query’, а остальную часть — через POST
По умолчанию размер URL ограничен 1 MiB, это можно изменить с помощью настройки http_max_uri_size.
В случае успеха вы получите код ответа 200 и результат в теле ответа.
Если произойдет ошибка, вы получите код ответа 500 и текстовое описание ошибки в теле ответа.
Запросы, отправляемые с помощью GET, доступны ‘только для чтения’. Это означает, что для запросов, изменяющих данные, можно использовать только метод POST.
Сам запрос можно передать либо в теле POST, либо в параметре URL. Рассмотрим несколько примеров.
В примере ниже для отправки запроса SELECT 1 используется curl. Обратите внимание на URL-кодирование пробела: %20.
curl 'http://localhost:8123/?query=SELECT%201'
В этом примере wget используется с параметрами -nv (без подробного вывода) и -O- для вывода результата в терминал.
В этом случае URL-кодирование пробела не требуется:
wget -nv -O- 'http://localhost:8123/?query=SELECT 1'
В этом примере мы отправляем необработанный HTTP-запрос через 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
Как видите, команда curl не очень удобна, поскольку пробелы в URL нужно экранировать.
Хотя wget сам экранирует всё, мы не рекомендуем его использовать, потому что он плохо работает по HTTP 1.1 с keep-alive и 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
Если часть запроса передаётся в параметре, а часть — в теле POST-запроса, между этими двумя частями данных вставляется символ перевода строки.
Например, это не сработает:
$ 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
По умолчанию данные возвращаются в формате TabSeparated.
Предложение FORMAT используется в запросе для указания любого другого формата. Например:
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
}
}
Вы можете использовать URL-параметр default_format или заголовок X-ClickHouse-Format, чтобы задать формат по умолчанию вместо TabSeparated.
$ echo 'SELECT 1 FORMAT Pretty' | curl 'http://localhost:8123/?' --data-binary @-
┏━━━┓
┃ 1 ┃
┡━━━┩
│ 1 │
└───┘
Вы можете использовать метод POST с параметризованными запросами. Параметры указываются в фигурных скобках с именем параметра и его типом, например {name:Type}. Значения параметров передаются через param_name:
$ curl -X POST -F 'query=select {p1:UInt8} + {p2:UInt8}' -F "param_p1=3" -F "param_p2=4" 'http://localhost:8123/'
7
INSERT-запросы через HTTP/HTTPS
Для INSERT-запросов необходим метод передачи данных POST. В этом случае начало запроса можно указать в параметре URL, а сами данные для вставки передать через POST. Данными для вставки может быть, например, дамп из MySQL с полями, разделёнными табуляцией. Таким образом, запрос INSERT заменяет команду LOAD DATA LOCAL INFILE из MySQL.
Чтобы создать таблицу:
$ echo 'CREATE TABLE t (a UInt8) ENGINE = Memory' | curl 'http://localhost:8123/' --data-binary @-
Чтобы использовать привычный запрос INSERT для вставки данных:
$ echo 'INSERT INTO t VALUES (1),(2),(3)' | curl 'http://localhost:8123/' --data-binary @-
Чтобы отправить данные отдельно от запроса:
$ echo '(4),(5),(6)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20VALUES' --data-binary @-
Можно указать любой формат данных. Например, можно указать формат ‘Values’ — тот же формат, который используется при выполнении INSERT INTO t VALUES:
$ echo '(7),(8),(9)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20FORMAT%20Values' --data-binary @-
Чтобы вставить данные из дампа, где значения разделены табуляцией, укажите соответствующий формат:
$ echo -ne '10\n11\n12\n' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20FORMAT%20TabSeparated' --data-binary @-
Чтобы посмотреть содержимое таблицы:
$ curl 'http://localhost:8123/?query=SELECT%20a%20FROM%20t'
7
8
9
10
11
12
1
2
3
4
5
6
Данные выводятся в случайном порядке из-за параллельной обработки запроса
Чтобы удалить таблицу:
$ echo 'DROP TABLE t' | curl 'http://localhost:8123/' --data-binary @-
Для успешных запросов, которые не возвращают таблицу с данными, тело ответа будет пустым.
Сжатие можно использовать для уменьшения сетевого трафика при передаче больших объёмов данных или для создания дампов, которые сразу записываются в сжатом виде.
При передаче данных можно использовать внутренний формат сжатия ClickHouse. Сжатые данные имеют нестандартный формат, и для работы с ними требуется программа clickhouse-compressor. Она по умолчанию устанавливается вместе с пакетом clickhouse-client.
Чтобы повысить эффективность вставки данных, отключите проверку контрольных сумм на стороне сервера с помощью настройки http_native_compression_disable_checksumming_on_decompress.
Если указать compress=1 в URL, сервер будет сжимать отправляемые вам данные. Если указать decompress=1 в URL, сервер будет распаковывать данные, которые вы передаёте методом POST.
Вы также можете использовать HTTP-сжатие. ClickHouse поддерживает следующие методы сжатия:
gzip
br
deflate
xz
zstd
lz4
bz2
snappy
Чтобы отправить сжатый запрос POST, добавьте заголовок запроса Content-Encoding: compression_method.
Чтобы ClickHouse сжимал ответ, добавьте в запрос заголовок Accept-Encoding: compression_method.
Уровень сжатия данных для всех методов сжатия можно настроить с помощью параметра http_zlib_compression_level.
Некоторые HTTP-клиенты по умолчанию могут распаковывать данные, полученные от сервера (для gzip и deflate), поэтому вы можете получить уже распакованные данные, даже если правильно используете настройки сжатия.
Чтобы отправить сжатые данные на сервер:
echo "SELECT 1" | gzip -c | \
curl -sS --data-binary @- -H 'Content-Encoding: gzip' 'http://localhost:8123/'
Чтобы получить с сервера архив со сжатыми данными:
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
Чтобы получить сжатые данные с сервера, используйте gunzip для распаковки данных:
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
Вы можете использовать параметр URL database или заголовок X-ClickHouse-Database, чтобы задать базу данных по умолчанию.
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
По умолчанию используется база данных, указанная в настройках сервера. Изначально это база данных default. При необходимости вы всегда можете явно указать базу данных, поставив точку перед именем таблицы.
Имя пользователя и пароль можно указать одним из трёх способов:
- С помощью базовой HTTP-аутентификации.
Например:
echo 'SELECT 1' | curl 'http://user:password@localhost:8123/' -d @-
- В URL-параметрах
user и password
Мы не рекомендуем использовать этот способ, так как параметр может быть записан в журнале веб-прокси и кэшироваться в браузере
Например:
echo 'SELECT 1' | curl 'http://localhost:8123/?user=user&password=password' -d @-
- Использование header ‘X-ClickHouse-User’ и ‘X-ClickHouse-Key’
Например:
echo 'SELECT 1' | curl -H 'X-ClickHouse-User: user' -H 'X-ClickHouse-Key: password' 'http://localhost:8123/' -d @-
Если имя пользователя не указано, используется имя default. Если пароль не указан, используется пустой пароль.
Вы также можете использовать параметры URL, чтобы задать любые настройки для обработки отдельного запроса или целых профилей настроек.
Например:
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
Дополнительную информацию см.:
Использование сеансов ClickHouse в HTTP-протоколе
Сеансы ClickHouse также можно использовать в HTTP-протоколе. Для этого добавьте к запросу GET-параметр session_id. В качестве идентификатора сеанса можно использовать любую строку.
По умолчанию сеанс завершается после 60 секунд бездействия. Чтобы изменить этот тайм-аут (в секундах), измените настройку default_session_timeout в конфигурации сервера или добавьте к запросу GET-параметр session_timeout.
Чтобы проверить состояние сеанса, используйте параметр session_check=1. В одном сеансе одновременно может выполняться только один запрос.
Информацию о прогрессе выполнения запроса можно получить из заголовков ответа X-ClickHouse-Progress. Для этого включите send_progress_in_http_headers.
Ниже приведен пример последовательности заголовков:
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"}
Возможны следующие поля заголовка:
| Поле заголовка | Описание |
|---|
read_rows | Количество прочитанных строк. |
read_bytes | Объём прочитанных данных в байтах. |
total_rows_to_read | Общее количество строк для чтения. |
written_rows | Количество записанных строк. |
written_bytes | Объём записанных данных в байтах. |
elapsed_ns | Время выполнения запроса в наносекундах. |
memory_usage | Объём памяти в байтах, использованный запросом. (Доступно с v25.11) |
Выполняющиеся запросы не останавливаются автоматически при потере HTTP-соединения. Парсинг и форматирование данных выполняются на стороне сервера, поэтому передача по сети может быть неэффективной.
Существуют следующие необязательные параметры:
| Параметры | Описание |
|---|
query_id (optional) | Можно передать как идентификатор запроса (любая строка). replace_running_query |
quota_key (optional) | Можно передать как ключ квоты (любая строка). “Квоты” |
HTTP-интерфейс позволяет передавать внешние данные (внешние временные таблицы) для выполнения запросов. Подробнее см. в разделе “Внешние данные для обработки запросов”.
Буферизацию ответа можно включить на стороне сервера. Для этого предусмотрены следующие URL-параметры:
buffer_size
wait_end_of_query
Также можно использовать следующие настройки:
buffer_size определяет количество байтов результата, которое нужно буферизовать в памяти сервера. Если тело результата превышает этот порог, буфер записывается в HTTP-канал, а оставшиеся данные отправляются в HTTP-канал напрямую.
Чтобы буферизовать ответ целиком, установите wait_end_of_query=1. В этом случае данные, которые не помещаются в памяти, будут буферизоваться во временном файле сервера.
Например:
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'
Используйте буферизацию, чтобы избежать ситуаций, когда ошибка при обработке запроса возникает уже после того, как клиенту были отправлены код ответа и HTTP-заголовки. В таком случае сообщение об ошибке записывается в конец тела ответа, и на стороне клиента её можно обнаружить только на этапе разбора.
Установка роли с помощью параметров запроса
Эта возможность была добавлена в ClickHouse 24.4.
В некоторых случаях перед выполнением самого оператора может потребоваться сначала установить назначенную роль.
Однако отправить SET ROLE и сам оператор вместе невозможно, так как мультиоператоры не поддерживаются:
curl -sS "http://localhost:8123" --data-binary "SET ROLE my_role;SELECT * FROM my_table;"
Приведённая выше команда вызывает ошибку:
Code: 62. DB::Exception: Syntax error (Multi-statements are not allowed)
Чтобы обойти это ограничение, используйте параметр запроса role:
curl -sS "http://localhost:8123?role=my_role" --data-binary "SELECT * FROM my_table;"
Это равносильно выполнению SET ROLE my_role перед оператором.
Кроме того, можно указать несколько параметров запроса role:
curl -sS "http://localhost:8123?role=my_role&role=my_other_role" --data-binary "SELECT * FROM my_table;"
В этом случае ?role=my_role&role=my_other_role эквивалентно выполнению SET ROLE my_role, my_other_role перед выполнением оператора.
Нюансы кодов HTTP-ответов
Из-за ограничений HTTP-протокола код ответа HTTP 200 не гарантирует, что запрос был выполнен успешно.
Вот пример:
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))
Причина такого поведения заключается в особенностях HTTP-протокола. Сначала отправляется HTTP-заголовок с HTTP-кодом 200, затем — HTTP-тело, а после этого ошибка вставляется в тело в виде обычного текста.
Это поведение не зависит от используемого формата, будь то Native, TSV или JSON; сообщение об ошибке всегда будет находиться в середине потока ответа.
Вы можете частично решить эту проблему, включив wait_end_of_query=1 (Буферизация ответа). В этом случае отправка HTTP-заголовка откладывается до тех пор, пока запрос не будет полностью обработан. Однако это не устраняет проблему полностью, поскольку результат по-прежнему должен помещаться в http_response_buffer_size, а другие настройки, такие как send_progress_in_http_headers, могут помешать задержке заголовка.
Единственный способ перехватить все ошибки — проанализировать HTTP-тело перед тем, как разбирать его в нужном формате.
Такие исключения в ClickHouse имеют единообразный формат, как показано ниже, независимо от того, какой формат используется (например, Native, TSV, JSON и т. д.), если http_write_exception_in_output_format=0 (по умолчанию). Это упрощает разбор и извлечение сообщений об ошибках на стороне клиента.
\r\n
__exception__\r\n
<TAG>\r\n
<error message>\r\n
<message_length> <TAG>\r\n
__exception__\r\n
Где <TAG> — это случайный тег длиной 16 байт, то есть тот же тег, который отправляется в заголовке ответа X-ClickHouse-Exception-Tag.
<error message> — это фактическое сообщение об исключении (точную длину можно найти в <message_length>). Весь описанный выше блок исключения может иметь размер до 16 КиБ.
Вот пример в формате 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__
Вот аналогичный пример, но в формате 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__
Вы можете создать запрос с параметрами и передать их значения через соответствующие параметры HTTP-запроса. Подробнее см. в разделе Запросы с параметрами для CLI.
$ curl -sS "<address>?param_id=2¶m_phrase=test" -d "SELECT * FROM table WHERE int_column = {id:UInt8} and string_column = {phrase:String}"
Табуляции в параметрах URL
Параметры запроса разбираются из формата “escaped”. У этого есть некоторые преимущества, например возможность однозначно разбирать значения NULL как \N. Это означает, что символ табуляции должен быть закодирован как \t (или как \ и символ табуляции). Например, ниже между abc и 123 стоит настоящий символ табуляции, а входная строка разбивается на два значения:
curl -sS "http://localhost:8123" -d "SELECT splitByChar('\t', 'abc 123')"
Однако, если вы попытаетесь закодировать настоящий символ табуляции как %09 в параметре URL, он не будет корректно разобран:
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))
Если вы используете URL-параметры, потребуется закодировать \t как %5C%09. Например:
curl -sS "http://localhost:8123?param_arg1=abc%5C%09123" -d "SELECT splitByChar('\t', {arg1:String})"
Предопределённый HTTP-интерфейс
ClickHouse поддерживает выполнение определённых запросов через HTTP-интерфейс. Например, записать данные в таблицу можно следующим образом:
$ echo '(4),(5),(6)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20VALUES' --data-binary @-
ClickHouse также поддерживает предопределённый HTTP-интерфейс, который упрощает интеграцию со сторонними инструментами, такими как Prometheus exporter. Давайте рассмотрим пример.
Прежде всего, добавьте этот раздел в файл конфигурации сервера.
http_handlers настраивается так, чтобы содержать несколько rule. ClickHouse сопоставляет полученные HTTP-запросы с предопределённым типом в rule, и первое совпавшее rule запускает обработчик. Затем ClickHouse выполнит соответствующий предопределённый запрос, если сопоставление прошло успешно.
<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>
Теперь вы можете напрямую запросить этот URL, чтобы получить данные в формате 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" "Количество выполняемых запросов"
# TYPE "Query" counter
"Query" 1
# HELP "Merge" "Количество выполняемых фоновых слияний"
# TYPE "Merge" counter
"Merge" 0
# HELP "PartMutation" "Количество мутаций (ALTER DELETE/UPDATE)"
# TYPE "PartMutation" counter
"PartMutation" 0
# HELP "ReplicatedFetch" "Количество частей данных, загружаемых с реплики"
# TYPE "ReplicatedFetch" counter
"ReplicatedFetch" 0
# HELP "ReplicatedSend" "Количество частей данных, отправляемых на реплики"
# TYPE "ReplicatedSend" counter
"ReplicatedSend" 0
* Connection #0 to host localhost left intact
* Connection #0 to host localhost left intact
Параметры конфигурации для http_handlers работают следующим образом.
В rule можно настроить следующие параметры:
method
headers
url
full_url
handler
Каждый из них описан ниже:
-
method отвечает за сопоставление части HTTP-запроса, содержащей метод. method полностью соответствует определению [method]
(https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) в HTTP-протоколе. Это необязательный параметр конфигурации. Если он не задан в
конфигурационном файле, сопоставление по части HTTP-запроса, содержащей метод, не выполняется.
-
url отвечает за сопоставление части URL (пути и строки запроса) HTTP-запроса.
Если url имеет префикс regex:, ожидается регулярное выражение в формате RE2.
Это необязательный параметр конфигурации. Если он не задан в конфигурационном файле, сопоставление по части URL HTTP-запроса не выполняется.
-
full_url — то же, что и url, но включает полный URL, то есть schema://host:port/path?query_string.
Обратите внимание: ClickHouse не поддерживает “virtual hosts”, поэтому host — это IP-адрес (а не значение заголовка Host).
-
empty_query_string — гарантирует, что в запросе отсутствует строка запроса (?query_string)
-
headers отвечают за сопоставление заголовков HTTP-запроса. Поддерживаются регулярные выражения RE2. Это необязательный
параметр конфигурации. Если они не заданы в конфигурационном файле, сопоставление по заголовкам HTTP-запроса не выполняется.
-
handler содержит основную логику обработки.
Он может иметь следующий type:
И следующие параметры:
query — используется с типом predefined_query_handler, выполняет запрос при вызове обработчика.
query_param_name — используется с типом dynamic_query_handler, извлекает и выполняет значение, соответствующее значению query_param_name в
параметрах HTTP-запроса.
status — используется с типом static, код состояния ответа.
content_type — используется с любым типом, content-type ответа.
http_response_headers — используется с любым типом, набор заголовков ответа. Также может использоваться для задания типа содержимого.
response_content — используется с типом static, содержимое ответа, отправляемое клиенту; при использовании префикса ‘file://’ или ‘config://’
содержимое берется из файла или конфигурации и отправляется клиенту.
user - пользователь, от имени которого выполняется запрос (пользователь по умолчанию — default).
Примечание: для этого пользователя не нужно указывать пароль.
Далее рассматриваются способы настройки для разных type.
predefined_query_handler поддерживает установку значений Settings и query_params. Вы можете настроить query для типа predefined_query_handler.
Значение query — это предопределённый запрос для predefined_query_handler, который ClickHouse выполняет при совпадении с HTTP-запросом; в ответ возвращается результат этого запроса. Это обязательный параметр конфигурации.
В следующем примере задаются значения настроек max_threads и max_final_threads, после чего выполняется запрос к системной таблице, чтобы проверить, были ли эти настройки успешно установлены.
Чтобы сохранить обработчики handlers по умолчанию, такие как query, play, ping, добавьте правило <defaults/>.
Например:
<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
Виртуальный параметр _request_body
Помимо параметров URL, заголовков и параметров запроса, predefined_query_handler поддерживает специальный виртуальный параметр _request_body.
Он содержит необработанное тело HTTP-запроса в виде строки.
Это позволяет создавать гибкие REST API, способные принимать данные в произвольных форматах и обрабатывать их в запросах.
Например, _request_body можно использовать для создания REST-конечной точки, которая принимает JSON-данные в POST-запросе и вставляет их в таблицу:
<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>
Затем вы можете отправлять данные на эту конечную точку:
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"}'
В одном predefined_query_handler поддерживается только один запрос.
В dynamic_query_handler запрос передаётся в виде параметра HTTP-запроса. Отличие состоит в том, что в predefined_query_handler запрос записывается в файле конфигурации. В dynamic_query_handler можно настроить query_param_name.
ClickHouse извлекает и выполняет значение, соответствующее query_param_name в URL HTTP-запроса. Значение query_param_name по умолчанию — /query. Это необязательный параметр конфигурации. Если в файле конфигурации он не определён, параметр не передаётся.
Чтобы поэкспериментировать с этой функциональностью, в следующем примере задаются значения max_threads и max_final_threads, а с помощью queries проверяется, были ли эти настройки успешно установлены.
Пример:
<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 может возвращать content_type, status и response_content. response_content позволяет возвращать указанное содержимое.
Например, чтобы вернуть сообщение “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 можно использовать, чтобы задать тип содержимого вместо 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!%
Найдите в конфигурации содержимое, отправляемое клиенту.
<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>%
Чтобы получить содержимое файла, отправьте клиенту:
<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 выполняет перенаправление 302 на location
Например, вот как можно автоматически добавить параметр set user в play для ClickHouse play:
<clickhouse>
<http_handlers>
<rule>
<methods>GET</methods>
<url>/play</url>
<handler>
<type>redirect</type>
<location>/play?user=play</location>
</handler>
</rule>
</http_handlers>
</clickhouse>
ClickHouse позволяет настраивать пользовательские HTTP-заголовки ответа, которые можно применять к любому настраиваемому типу обработчика. Эти заголовки можно задать с помощью настройки http_response_headers, которая принимает пары ключ-значение, содержащие имена заголовков и их значения. Эта возможность особенно полезна для настройки пользовательских заголовков безопасности, политик CORS и любых других требований к HTTP-заголовкам в HTTP-интерфейсе ClickHouse.
Например, можно настроить заголовки для:
- Обычных эндпоинтов запросов
- Веб-интерфейса
- Проверки работоспособности.
Также можно указать common_http_response_headers. Они будут применяться ко всем HTTP-обработчикам, определённым в конфигурации.
Эти заголовки будут включаться в HTTP-ответ для каждого настроенного обработчика.
В примере ниже каждый ответ сервера будет содержать два пользовательских заголовка: X-My-Common-Header и 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>
Корректный JSON/XML-ответ при исключении во время потоковой передачи по HTTP
Во время выполнения запроса по HTTP может возникнуть исключение, когда часть данных уже была отправлена. Обычно в таком случае исключение отправляется клиенту в виде обычного текста.
Даже если для вывода данных использовался определённый формат, результат может стать недопустимым с точки зрения этого формата.
Чтобы этого избежать, можно использовать настройку http_write_exception_in_output_format (по умолчанию отключена), которая укажет ClickHouse записывать исключение в указанном формате (в настоящее время поддерживаются форматы XML и JSON*).
Примеры:
$ 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>
Последнее изменение 10 июня 2026 г.