跳至主要内容
跳至主要内容

HTTP 接口

先决条件

对于本文中的示例,您需要

  • 有一个正在运行的 ClickHouse 服务器
  • 安装 curl。在 Ubuntu 或 Debian 上,运行 sudo apt install curl 或参考此 文档 获取安装说明。

概述

HTTP 接口允许您以 REST API 的形式,在任何平台和任何编程语言中使用 ClickHouse。HTTP 接口比原生接口更有限,但它具有更好的语言支持。

默认情况下,clickhouse-server 监听以下端口

  • 端口 8123 用于 HTTP
  • 端口 8443 用于 HTTPS,可以启用

如果您发出不带任何参数的 GET / 请求,将返回 200 响应代码以及字符串 "Ok。"。

$ curl 'https://:8123/'
Ok.

"Ok。" 是在 http_server_default_response 中定义的默认值,如果需要可以更改它。

另请参阅:HTTP 响应代码注意事项

Web 用户界面

ClickHouse 包含一个 Web 用户界面,可以从以下地址访问

https://:8123/play

Web UI 支持在查询运行时显示进度、取消查询和流式传输结果。它有一个秘密功能,可以为查询管道显示图表和图形。

在成功执行查询后,会显示一个下载按钮,允许您以各种格式(包括 CSV、TSV、JSON、JSONLines、Parquet、Markdown 或 ClickHouse 支持的任何自定义格式)下载查询结果。下载功能使用查询缓存来有效地检索结果,而无需重新执行查询。即使 UI 只显示了许多页面中的一个,它也会下载完整的结果集。

Web UI 专为像您这样的专业人士设计。

在健康检查脚本中使用 GET /ping 请求。此处理程序始终返回 "Ok。"(结尾带换行符)。从版本 18.12.13 开始可用。另请参阅 /replicas_status 以检查副本的延迟。

$ curl 'https://:8123/ping'
Ok.
$ curl 'https://: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 参数中。让我们看一些例子。

在下面的示例中,curl 用于发送查询 SELECT 1。请注意空格的 URL 编码:%20

curl 'https://:8123/?query=SELECT%201'
1

在此示例中,wget 使用 -nv(非详细)和 -O- 参数将结果输出到终端。在这种情况下,不需要对空格使用 URL 编码

wget -nv -O- 'https://:8123/?query=SELECT 1'
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 会自行转义所有内容,但我们不建议使用它,因为它在使用 keep-alive 和 Transfer-Encoding: chunked 时在 HTTP 1.1 上效果不佳。

$ echo 'SELECT 1' | curl 'https://:8123/' --data-binary @-
1

$ echo 'SELECT 1' | curl 'https://:8123/?query=' --data-binary @-
1

$ echo '1' | curl 'https://:8123/?query=SELECT' --data-binary @-
1

如果查询的一部分通过参数发送,另一部分通过 POST 发送,则会在这两个数据部分之间插入一个换行符。例如,这将不起作用

$ echo 'ECT 1' | curl 'https://: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- 'https://: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
    }
}

您可以使用 default_format URL 参数或 X-ClickHouse-Format 标头来指定其他于 TabSeparated 的默认格式。

$ echo 'SELECT 1 FORMAT Pretty' | curl 'https://: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" 'https://:8123/'

7

通过 HTTP/HTTPS 进行插入查询

对于 INSERT 查询,使用 POST 方法传输数据是必要的。在这种情况下,您可以在 URL 参数中写入查询的开头,并使用 POST 传递要插入的数据。要插入的数据可以是来自 MySQL 的制表符分隔的转储,例如。这样,INSERT 查询就取代了 MySQL 中的 LOAD DATA LOCAL INFILE

示例

要创建表

$ echo 'CREATE TABLE t (a UInt8) ENGINE = Memory' | curl 'https://:8123/' --data-binary @-

要使用熟悉的 INSERT 查询进行数据插入

$ echo 'INSERT INTO t VALUES (1),(2),(3)' | curl 'https://:8123/' --data-binary @-

要单独发送数据和查询

$ echo '(4),(5),(6)' | curl 'https://:8123/?query=INSERT%20INTO%20t%20VALUES' --data-binary @-

可以指定任何数据格式。例如,可以指定与编写 INSERT INTO t VALUES 时使用的格式相同的“Values”格式

$ echo '(7),(8),(9)' | curl 'https://:8123/?query=INSERT%20INTO%20t%20FORMAT%20Values' --data-binary @-

要插入制表符分隔的转储数据,请指定相应的格式

$ echo -ne '10\n11\n12\n' | curl 'https://:8123/?query=INSERT%20INTO%20t%20FORMAT%20TabSeparated' --data-binary @-

要读取表的内容

$ curl 'https://:8123/?query=SELECT%20a%20FROM%20t'
7
8
9
10
11
12
1
2
3
4
5
6
注意

由于并行查询处理,数据以随机顺序输出

要删除表

$ echo 'DROP TABLE t' | curl 'https://:8123/' --data-binary @-

对于不返回数据表的成功请求,将返回一个空响应体。

压缩

可以使用压缩来减少传输大量数据时的网络流量,或者用于创建立即压缩的转储。

您可以使用内部 ClickHouse 压缩格式传输数据。压缩数据具有非标准格式,您需要 clickhouse-compressor 程序来处理它。它默认与 clickhouse-client 包一起安装。

为了提高数据插入效率,通过使用 http_native_compression_disable_checksumming_on_decompress 设置禁用服务器端校验和验证。

如果您在 URL 中指定 compress=1,服务器将压缩发送给您的数据。如果您在 URL 中指定 decompress=1,服务器将解压缩您通过 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 客户端可能会默认解压缩来自服务器的数据(使用 gzipdeflate),并且您可能会获得解压缩的数据,即使您正确使用了压缩设置。

示例

要将压缩数据发送到服务器

echo "SELECT 1" | gzip -c | \
curl -sS --data-binary @- -H 'Content-Encoding: gzip' 'https://:8123/'

要从服务器接收压缩数据存档

curl -vsS "https://: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 "https://:8123/?enable_http_compression=1" \
-H 'Accept-Encoding: gzip' -d 'SELECT number FROM system.numbers LIMIT 3' | gunzip -
0
1
2

默认数据库

您可以使用 database URL 参数或 X-ClickHouse-Database 标头来指定默认数据库。

echo 'SELECT number FROM numbers LIMIT 10' | curl 'https://:8123/?database=system' --data-binary @-
0
1
2
3
4
5
6
7
8
9

默认情况下,在服务器设置中注册的数据库用作默认数据库。默认情况下,这是名为 default 的数据库。或者,您始终可以使用点在表名前面指定数据库。

身份验证

用户名和密码可以通过以下三种方式指示

  1. 使用 HTTP Basic Authentication。

例如

echo 'SELECT 1' | curl 'http://user:password@localhost:8123/' -d @-
  1. userpassword URL 参数中
注意

我们不建议使用此方法,因为该参数可能会被 Web 代理记录并在浏览器中缓存

例如

echo 'SELECT 1' | curl 'https://:8123/?user=user&password=password' -d @-
  1. 使用 'X-ClickHouse-User' 和 'X-ClickHouse-Key' 标头

例如

echo 'SELECT 1' | curl -H 'X-ClickHouse-User: user' -H 'X-ClickHouse-Key: password' 'https://:8123/' -d @-

如果未指定用户名,则使用 default 名称。如果未指定密码,则使用空密码。您还可以使用 URL 参数来指定用于处理单个查询或整个设置配置文件的任何设置。

例如

https://:8123/?profile=web&max_rows_to_read=1000000000&query=SELECT+1
$ echo 'SELECT number FROM system.numbers LIMIT 10' | curl 'https://:8123/?' --data-binary @-
0
1
2
3
4
5
6
7
8
9

更多信息请参见

在 HTTP 协议中使用 ClickHouse 会话

您也可以在 HTTP 协议中使用 ClickHouse 会话。为此,您需要将 session_id GET 参数添加到请求中。您可以将任何字符串用作会话 ID。

默认情况下,会话在 60 秒不活动后终止。要更改此超时时间(以秒为单位),请修改服务器配置中的 default_session_timeout 设置,或将 session_timeout GET 参数添加到请求中。

要检查会话状态,请使用 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(可选)可以作为查询 ID 传递(任何字符串)。 replace_running_query
quota_key(可选)可以作为配额键传递(任何字符串)。 “配额”

HTTP 接口允许传递外部数据(外部临时表)进行查询。有关更多信息,请参见 “外部数据用于查询处理”

响应缓冲

响应缓冲可以在服务器端启用。为此提供了以下 URL 参数

  • buffer_size
  • wait_end_of_query

可以使用以下设置

buffer_size 确定结果中要缓冲在服务器内存中的字节数。如果结果体大于此阈值,则缓冲区将写入 HTTP 通道,其余数据将直接发送到 HTTP 通道。

要确保缓冲整个响应,请设置 wait_end_of_query=1。在这种情况下,未存储在内存中的数据将被缓冲到临时服务器文件中。

例如

curl -sS 'https://: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 "https://: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 "https://:8123?role=my_role" --data-binary "SELECT * FROM my_table;"

这等效于在语句之前执行 SET ROLE my_role

此外,还可以指定多个 role 查询参数

curl -sS "https://: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 "https://: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 主体,最后将错误注入到主体中作为纯文本。

无论使用哪种格式(例如 NativeTSVJSON),这种行为都是独立的;错误消息始终位于响应流的中间。

您可以通过启用 wait_end_of_query=1响应缓冲)来缓解此问题。在这种情况下,将延迟发送 HTTP 标头,直到解决整个查询。但是,这并不能完全解决问题,因为结果仍然必须适合 http_response_buffer_size,并且其他设置(如 send_progress_in_http_headers)可能会干扰标头的延迟。

提示

捕获所有错误的唯一方法是在使用所需格式解析之前分析 HTTP 主体。

http_write_exception_in_output_format=0(默认值)时,ClickHouse 中的此类异常具有一致的异常格式,无论使用哪种格式(例如 NativeTSVJSON 等)。这使得在客户端解析和提取错误消息变得容易。

\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 KiB。

这是一个 JSON 格式的例子

$ curl -v -Ss "https://: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 "https://: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&param_phrase=test" -d "SELECT * FROM table WHERE int_column = {id:UInt8} and string_column = {phrase:String}"

URL 参数中的制表符

URL 参数是从“转义”格式解析的。这有一些好处,例如可以明确地将空值解析为 \N。这意味着制表符字符应编码为 \t(或 \ 和一个制表符)。例如,以下内容在 abc123 之间包含一个实际的制表符,并且输入字符串被拆分为两个值

curl -sS "https://:8123" -d "SELECT splitByChar('\t', 'abc      123')"
['abc','123']

但是,如果您尝试在 URL 参数中使用 %09 编码实际的制表符,则无法正确解析它

curl -sS "https://: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 "https://:8123?param_arg1=abc%5C%09123" -d "SELECT splitByChar('\t', {arg1:String})"
['abc','123']

预定义的 HTTP 接口

ClickHouse 通过 HTTP 接口支持特定的查询。例如,您可以将数据写入表如下

$ echo '(4),(5),(6)' | curl 'https://:8123/?query=INSERT%20INTO%20t%20VALUES' --data-binary @-

ClickHouse 还支持预定义的 HTTP 接口,它可以帮助您更轻松地与第三方工具(如 Prometheus exporter)集成。让我们看一个例子。

首先,将此部分添加到您的服务器配置文件中。

http_handlers 配置为包含多个 rule。ClickHouse 将接收到的 HTTP 请求与 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 'https://: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" "Number of executing queries"
# TYPE "Query" counter
"Query" 1

# HELP "Merge" "Number of executing background merges"
# TYPE "Merge" counter
"Merge" 0

# HELP "PartMutation" "Number of mutations (ALTER DELETE/UPDATE)"
# TYPE "PartMutation" counter
"PartMutation" 0

# HELP "ReplicatedFetch" "Number of data parts being fetched from replica"
# TYPE "ReplicatedFetch" counter
"ReplicatedFetch" 0

# HELP "ReplicatedSend" "Number of data parts being sent to replicas"
# 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 完全符合 HTTP 协议中 [method] 的定义
    (https://mdn.org.cn/en-US/docs/Web/HTTP/Methods)。这是一个可选的配置。如果未在
    配置文件中定义,则它不会匹配 HTTP 请求的方法部分。

  • url 负责匹配 HTTP 请求的 URL 部分(路径和查询字符串)。如果 url 前缀为 regex:,则它期望 RE2 的正则表达式。这是一个可选的配置。如果未在配置文件中定义,则它不会匹配 HTTP 请求的 URL 部分。

  • full_urlurl 相同,但是,包括完整的 URL,即 schema://host:port/path?query_string。请注意,ClickHouse 不支持“虚拟主机”,因此 host 是 IP 地址(而不是 Host 标头的值)。

  • empty_query_string - 确保请求中没有查询字符串(?query_string

  • headers 负责匹配 HTTP 请求的标头部分。它与 RE2 的正则表达式兼容。这是一个可选的配置。如果未在配置文件中定义,则它不会匹配 HTTP 请求的标头部分。

  • handler 包含主要的处理部分。

    它可以具有以下 type

    以及以下参数

    • query — 与 predefined_query_handler 类型一起使用,在调用处理程序时执行查询。
    • query_param_name — 与 dynamic_query_handler 类型一起使用,提取并执行 HTTP 请求参数中 query_param_name 对应的值。
    • status — 与 static 类型一起使用,响应状态码。
    • content_type — 与任何类型一起使用,响应 content-type
    • http_response_headers — 与任何类型一起使用,响应标头映射。也可以用来设置 content type。
    • response_content — 与 static 类型一起使用,发送到客户端的响应内容,当使用前缀 'file://' 或 'config://' 时,从文件或配置中查找内容并发送到客户端。
    • user - 从哪个用户执行查询(默认用户是 default)。注意,您不需要为该用户指定密码。

接下来讨论不同 type 的配置方法。

predefined_query_handler

predefined_query_handler 支持设置 Settingsquery_params 值。可以在 predefined_query_handler 类型中配置 query

query 值是 predefined_query_handler 的预定义查询,当 HTTP 请求匹配并且查询的结果返回时,ClickHouse 会执行该查询。这是一个必须的配置。

以下示例定义了 max_threadsmax_final_threads 设置的值,然后查询系统表以检查这些设置是否已成功设置。

注意

要保留默认的 handlers,例如 queryplay 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' 'https://: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 端点,该端点接受 POST 请求中的 JSON 数据并将其插入到表中

<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 'https://:8123/api/events?id=123' \
  -H 'Content-Type: application/json' \
  -d '{"user": "john", "action": "login", "timestamp": "2024-01-01T10:00:00Z"}'
注意

在一个 predefined_query_handler 中只支持一个 query

dynamic_query_handler

dynamic_query_handler 中,查询以 HTTP 请求参数的形式编写。区别在于,在 predefined_query_handler 中,查询在配置文件中编写。可以在 dynamic_query_handler 中配置 query_param_name

ClickHouse 从 HTTP 请求的 URL 中提取并执行与 query_param_name 值对应的值。query_param_name 的默认值为 /query。这是一个可选配置。如果在配置文件中没有定义,则不传递该参数。

为了试验此功能,以下示例定义了 max_threadsmax_final_threadsqueries 设置是否已成功设置。

示例

<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'  'https://:8123/own?max_threads=1&max_final_threads=2&param_name_1=max_threads&param_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

static 可以返回 content_typestatusresponse_contentresponse_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>
                #highlight-next-line
                <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' 'https://: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' 'https://: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' 'https://: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' 'https://: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

redirect 将执行 302 重定向到 location

例如,这样可以自动为 ClickHouse play 设置用户为 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>

HTTP 响应头

ClickHouse 允许您配置自定义 HTTP 响应头,这些响应头可以应用于可以配置的任何类型的处理程序。可以使用 http_response_headers 设置来设置这些头,该设置接受键值对,表示头名称及其值。此功能对于实施自定义安全头、CORS 策略或 ClickHouse HTTP 接口中的任何其他 HTTP 头要求特别有用。

例如,您可以为以下内容配置头:

  • 常规查询端点
  • Web UI
  • 健康检查。

也可以指定 common_http_response_headers。这些将应用于配置中定义的所有 http 处理程序。

这些头将包含在为每个配置的处理程序 HTTP 响应中。

在下面的示例中,每个服务器响应都将包含两个自定义头:X-My-Common-HeaderX-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>

HTTP 流期间发生异常时有效的 JSON/XML 响应

虽然查询执行发生在 HTTP 上,但在已经发送了部分数据时可能会发生异常。通常,异常以纯文本形式发送到客户端。即使使用了特定的数据格式来输出数据,并且输出在指定的数据格式方面可能无效。为了防止这种情况,您可以使用设置 http_write_exception_in_output_format(默认禁用),它将告诉 ClickHouse 以指定格式写入异常(当前支持 XML 和 JSON* 格式)。

示例

$ curl 'https://: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 'https://: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>
    © . This site is unofficial and not affiliated with ClickHouse, Inc.