> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-fbfa8bee.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> ClickHouse HTTP 接口文档。该接口支持从任何平台和编程语言通过 REST API 访问 ClickHouse

# HTTP 接口

export const Image = ({img, alt, size}) => {
  return <Frame>
      <img src={img} alt={alt} />
    </Frame>;
};

<div id="prerequisites">
  ## 前置条件
</div>

要运行本文中的示例，你需要：

* 有一个正在运行的 ClickHouse server 实例
* 已安装 `curl`。在 Ubuntu 或 Debian 上，运行 `sudo apt install curl`，或参阅此[文档](https://curl.se/download.html)了解安装说明。

<div id="overview">
  ## 概述
</div>

HTTP 接口 允许你以 REST API 的形式，在任何平台上通过任何编程语言使用 ClickHouse。HTTP 接口 的功能比 native interface 更受限，但语言支持更好。

默认情况下，`clickhouse-server` 监听以下端口：

* 8123 端口用于 HTTP
* 可启用 8443 端口用于 HTTPS

如果发起不带任何参数的 `GET /` 请求，则会返回 200 响应码以及字符串 "Ok."：

```bash theme={null}
$ curl 'http://localhost:8123/'
Ok.
```

"Ok." 是 [`http_server_default_response`](/zh/reference/settings/server-settings/settings#http_server_default_response) 中定义的默认值，可按需更改。

另请参见：[HTTP 响应代码注意事项](#http_response_codes_caveats)。

<div id="web-ui">
  ## Web 用户界面
</div>

ClickHouse 提供了一个 Web 用户界面，可通过以下地址访问：

```text theme={null}
http://localhost:8123/play
```

web UI 支持在查询运行期间显示进度、取消查询以及流式传输结果。
它还提供了一项用于显示查询管道图表和图形的隐藏功能。

查询成功执行后，会出现一个下载按钮，允许您以多种格式下载查询结果，包括 CSV、TSV、JSON、JSONLines、Parquet、Markdown，以及 ClickHouse 支持的任何自定义格式。下载功能使用查询缓存高效获取结果，而无需重新执行查询。即使 UI 只显示了多页结果中的一页，它也会下载完整结果集。

web UI 专为像您这样的专业用户而设计。

<Image img="https://mintcdn.com/private-7c7dfe99-mintlify-fbfa8bee/Z1HvIxdS-kNnO1Sa/images/play.png?fit=max&auto=format&n=Z1HvIxdS-kNnO1Sa&q=85&s=b191ea87af099f4f2f623ca6584cfa26" size="md" alt="ClickHouse Web UI 截图" width="1078" height="383" data-path="images/play.png" />

在健康检查脚本中，请使用 `GET /ping` 请求。此处理程序始终返回 "Ok." (末尾带有一个换行符) 。自 18.12.13 版本起可用。另请参阅 `/replicas_status` 以检查副本延迟。

```bash theme={null}
$ curl 'http://localhost:8123/ping'
Ok.
$ curl 'http://localhost:8123/replicas_status'
Ok.
```

<div id="querying">
  ## 通过 HTTP/HTTPS 查询
</div>

通过 HTTP/HTTPS 查询有三种方式：

* 将请求作为 URL 的 'query' 参数发送
* 使用 POST 方法。
* 在 'query' 参数中发送查询的开头部分，其余部分通过 POST 发送

<Note>
  默认情况下，URL 大小限制为 1 MiB，可通过 `http_max_uri_size` 设置修改。
</Note>

如果成功，你会收到 200 响应码，结果位于响应体中。
如果发生错误，你会收到 500 响应码，响应体中会包含错误描述文本。

使用 GET 的请求是 'readonly'。这意味着，对于会修改数据的查询，只能使用 POST 方法。
你可以将查询语句放在 POST 请求体中发送，也可以通过 URL 参数发送。下面来看一些示例。

在下面的示例中，使用 curl 发送查询 `SELECT 1`。请注意，空格需要进行 URL 编码：`%20`。

```bash title="command" theme={null}
curl 'http://localhost:8123/?query=SELECT%201'
```

```response title="Response" theme={null}
1
```

在此示例中，使用 wget 的 `-nv` (非冗长) 和 `-O-` 参数将结果输出到终端。
在这种情况下，无需对空格进行 URL 编码：

```bash title="command" theme={null}
wget -nv -O- 'http://localhost:8123/?query=SELECT 1'
```

```response theme={null}
1
```

在此示例中，我们通过管道将原始 HTTP 请求发送到 netcat：

```bash title="command" theme={null}
echo -ne 'GET /?query=SELECT%201 HTTP/1.0\r\n\r\n' | nc localhost 8123
```

```response title="response" theme={null}
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 的表现并不好。

```bash theme={null}
$ 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 传递，那么这两个数据部分之间会插入一个换行符。
例如，下面这样是行不通的：

```bash theme={null}
$ 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`](/zh/reference/formats/TabSeparated/TabSeparated) 格式返回。

可在查询中使用 `FORMAT` 子句来指定其他任意格式。例如：

```bash title="command" theme={null}
wget -nv -O- 'http://localhost:8123/?query=SELECT 1, 2, 3 FORMAT JSON'
```

```response title="Response" theme={null}
{
    "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` 以外的格式。

```bash theme={null}
$ echo 'SELECT 1 FORMAT Pretty' | curl 'http://localhost:8123/?' --data-binary @-
┏━━━┓
┃ 1 ┃
┡━━━┩
│ 1 │
└───┘
```

您可以使用 POST 方法执行参数化查询。参数通过花括号指定，并包含参数名称和类型，例如 `{name:Type}`。参数值通过 `param_name` 传入：

```bash theme={null}
$ curl -X POST -F 'query=select {p1:UInt8} + {p2:UInt8}' -F "param_p1=3" -F "param_p2=4" 'http://localhost:8123/'

7
```

<div id="insert-queries">
  ## 通过 HTTP/HTTPS 执行插入查询
</div>

执行 `INSERT` 查询时，必须使用 `POST` 方法传输数据。在这种情况下，你可以将查询开头部分写在 URL 参数中，再通过 POST 传递要插入的数据。要插入的数据例如可以是从 MySQL 导出的制表符分隔转储文件。这样，`INSERT` 查询就相当于替代了 MySQL 中的 `LOAD DATA LOCAL INFILE`。

<div id="examples">
  ### 示例
</div>

创建表：

```bash theme={null}
$ echo 'CREATE TABLE t (a UInt8) ENGINE = Memory' | curl 'http://localhost:8123/' --data-binary @-
```

如需使用常见的 `INSERT` 查询插入数据：

```bash theme={null}
$ echo 'INSERT INTO t VALUES (1),(2),(3)' | curl 'http://localhost:8123/' --data-binary @-
```

若要将数据与查询分开发送：

```bash theme={null}
$ echo '(4),(5),(6)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20VALUES' --data-binary @-
```

可以指定任何数据格式。例如，可以指定 'Values' 格式，它与在编写 `INSERT INTO t VALUES` 时使用的格式相同：

```bash theme={null}
$ echo '(7),(8),(9)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20FORMAT%20Values' --data-binary @-
```

要从以制表符分隔的转储中插入数据，请指定相应的格式：

```bash theme={null}
$ echo -ne '10\n11\n12\n' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20FORMAT%20TabSeparated' --data-binary @-
```

要查看表内容：

```bash theme={null}
$ curl 'http://localhost:8123/?query=SELECT%20a%20FROM%20t'
7
8
9
10
11
12
1
2
3
4
5
6
```

<Note>
  由于查询处理是并行进行的，数据会按随机顺序输出
</Note>

要删除该表：

```bash theme={null}
$ echo 'DROP TABLE t' | curl 'http://localhost:8123/' --data-binary @-
```

对于未返回数据表的成功请求，响应体为空。

<div id="compression">
  ## 压缩
</div>

压缩可用于在传输大量数据时减少网络流量，也可用于创建压缩后的转储文件。

传输数据时，您可以使用 ClickHouse 的内部压缩格式。压缩后的数据采用非标准格式，因此需要使用 `clickhouse-compressor` 程序来处理。该程序默认随 `clickhouse-client` 软件包一起安装。

为提高数据插入效率，请使用 [`http_native_compression_disable_checksumming_on_decompress`](/zh/reference/settings/session-settings#http_native_compression_disable_checksumming_on_decompress) 设置禁用服务器端的校验和验证。

如果您在 URL 中指定 `compress=1`，服务器会压缩发送给您的数据。如果您在 URL 中指定 `decompress=1`，服务器会解压您通过 `POST` 方法传入的数据。

您也可以选择使用 [HTTP 压缩](https://en.wikipedia.org/wiki/HTTP_compression)。ClickHouse 支持以下[压缩方法](https://en.wikipedia.org/wiki/HTTP_compression#Content-Encoding_tokens)：

* `gzip`
* `br`
* `deflate`
* `xz`
* `zstd`
* `lz4`
* `bz2`
* `snappy`

要发送压缩的 `POST` 请求，请附加请求头 `Content-Encoding: compression_method`。

要让 ClickHouse 压缩响应，请在请求中附加 `Accept-Encoding: compression_method` 请求头。

您可以使用 [`http_zlib_compression_level`](/zh/reference/settings/session-settings#http_zlib_compression_level) 设置，为所有压缩方法配置数据压缩级别。

<Info>
  某些 HTTP 客户端可能默认会解压来自服务器的数据 (如 `gzip` 和 `deflate`) ，因此即使您正确使用了压缩设置，也可能收到解压后的数据。
</Info>

<div id="examples-compression">
  ## 示例
</div>

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

```bash theme={null}
echo "SELECT 1" | gzip -c | \
curl -sS --data-binary @- -H 'Content-Encoding: gzip' 'http://localhost:8123/'
```

要从服务器接收压缩数据归档文件：

```bash theme={null}
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 获取解压后的数据：

```bash theme={null}
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
```

<div id="default-database">
  ## 默认数据库
</div>

你可以使用 URL 参数 `database` 或 `X-ClickHouse-Database` 请求头来指定默认数据库。

```bash theme={null}
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`。或者，你也可以始终在表名前加上点号来指定数据库。

<div id="authentication">
  ## 身份验证
</div>

可以通过以下三种方式之一提供用户名和密码：

1. 使用 HTTP Basic 身份验证。

例如：

```bash theme={null}
echo 'SELECT 1' | curl 'http://user:password@localhost:8123/' -d @-
```

2. 在 `user` 和 `password` URL 参数中

<Warning>
  我们不建议使用这种方法，因为这些参数可能会被 Web 代理记录，并缓存在浏览器中
</Warning>

例如：

```bash theme={null}
echo 'SELECT 1' | curl 'http://localhost:8123/?user=user&password=password' -d @-
```

3. 使用 'X-ClickHouse-User' 和 'X-ClickHouse-Key' 请求头

例如：

```bash theme={null}
echo 'SELECT 1' | curl -H 'X-ClickHouse-User: user' -H 'X-ClickHouse-Key: password' 'http://localhost:8123/' -d @-
```

如果未指定用户名，则使用 `default`。如果未指定密码，则使用空密码。
你还可以使用 URL 参数，为处理单个查询指定任意设置，或指定整个 profile 的设置。

例如：

```text theme={null}
http://localhost:8123/?profile=web&max_rows_to_read=1000000000&query=SELECT+1
```

```bash theme={null}
$ echo 'SELECT number FROM system.numbers LIMIT 10' | curl 'http://localhost:8123/?' --data-binary @-
0
1
2
3
4
5
6
7
8
9
```

更多信息，请参阅：

* [设置](/zh/reference/settings/session-settings)
* [SET](/zh/reference/statements/set)

<div id="using-clickhouse-sessions-in-the-http-protocol">
  ## 在 HTTP 协议中使用 ClickHouse 会话
</div>

你也可以在 HTTP 协议中使用 ClickHouse 会话。为此，需要在请求中添加 `session_id` `GET` 参数。你可以使用任意字符串作为会话 ID。

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

要检查会话状态，请使用 `session_check=1` 参数。单个会话中一次只能执行一个查询。

你可以在 `X-ClickHouse-Progress` 响应请求头中获取有关查询进度的信息。为此，请启用 [`send_progress_in_http_headers`](/zh/reference/settings/session-settings#send_progress_in_http_headers)。

下面是一个请求头序列示例：

```text theme={null}
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)  | 可作为查询 ID 传入 (任意字符串) 。[`replace_running_query`](/zh/reference/settings/session-settings#replace_running_query) |
| `quota_key` (optional) | 可作为配额键传入 (任意字符串) 。["Quotas"](/zh/concepts/features/configuration/server-config/quotas)                        |

HTTP 接口支持传递外部数据 (外部临时表) 用于查询。更多信息，请参阅["External data for query processing"](/zh/reference/engines/table-engines/special/external-data)。

<div id="response-buffering">
  ## 响应缓冲
</div>

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

* `buffer_size`
* `wait_end_of_query`

也可以使用以下设置：

* [`http_response_buffer_size`](/zh/reference/settings/session-settings#http_response_buffer_size)
* [`http_wait_end_of_query`](/zh/reference/settings/session-settings#http_wait_end_of_query)

`buffer_size` 用于指定在服务器内存中为结果缓冲的字节数。如果结果体大于该阈值，缓冲区中的内容会写入 HTTP 通道，其余数据将直接发送到 HTTP 通道。

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

例如：

```bash theme={null}
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'
```

<Tip>
  使用缓冲可避免这样一种情况：在响应状态码和 HTTP 请求头已发送给客户端之后，才发生查询处理错误。在这种情况下，错误信息会写在响应体末尾，而客户端只能在解析阶段检测到该错误。
</Tip>

<div id="setting-role-with-query-parameters">
  ## 使用查询参数设置角色
</div>

此功能已在 ClickHouse 24.4 中引入。

在某些特定场景下，可能需要先设置已授予的角色，再执行语句本身。
但是，无法将 `SET ROLE` 与该语句一并发送，因为不允许使用多语句：

```bash theme={null}
curl -sS "http://localhost:8123" --data-binary "SET ROLE my_role;SELECT * FROM my_table;"
```

上述命令会报错：

```sql theme={null}
Code: 62. DB::Exception: Syntax error (Multi-statements are not allowed)
```

为解决这一限制，请改用 `role` 查询参数：

```bash theme={null}
curl -sS "http://localhost:8123?role=my_role" --data-binary "SELECT * FROM my_table;"
```

这等同于在该语句前执行 `SET ROLE my_role`。

此外，还可以指定多个 `role` 查询参数：

```bash theme={null}
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`。

<div id="http_response_codes_caveats">
  ## HTTP 响应状态码注意事项
</div>

由于 HTTP 协议本身的限制，HTTP 200 响应码并不保证查询已成功。

例如：

```bash theme={null}
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 请求头会先以 200 HTTP 状态码发送，随后发送 HTTP body，而错误则会以纯文本形式插入到 body 中。

这种行为与所使用的格式无关，无论是 `Native`、`TSV` 还是 `JSON`；错误消息总是会出现在响应流的中间。

你可以通过启用 `wait_end_of_query=1` ([响应缓冲](#response-buffering)) 来缓解这个问题。在这种情况下，HTTP 请求头会延迟到整个查询处理完成后才发送。不过，这并不能彻底解决问题，因为结果仍然必须能够容纳在 [`http_response_buffer_size`](/zh/reference/settings/session-settings#http_response_buffer_size) 中，而且像 [`send_progress_in_http_headers`](/zh/reference/settings/session-settings#send_progress_in_http_headers) 这样的其他设置也可能会影响请求头的延迟发送。

<Tip>
  要捕获所有错误，唯一的方法是在按所需格式解析 HTTP body 之前先对其进行分析。
</Tip>

当 `http_write_exception_in_output_format=0` (默认值) 时，ClickHouse 中这类异常都会采用如下所示的一致格式，而与所使用的格式无关 (例如 `Native`、`TSV`、`JSON` 等) 。这使得客户端更容易解析并提取错误消息。

```text theme={null}
\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` 格式的示例

```bash theme={null}
$ 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` 格式

```bash theme={null}
$ 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__
```

<div id="cli-queries-with-parameters">
  ## 带参数的查询
</div>

您可以创建带参数的查询，并通过相应的 HTTP 请求参数传入参数值。更多信息，请参见[CLI 中的带参数查询](/zh/concepts/features/interfaces/client#cli-queries-with-parameters)。

<div id="examples">
  ### 示例
</div>

```bash theme={null}
$ curl -sS "<address>?param_id=2&param_phrase=test" -d "SELECT * FROM table WHERE int_column = {id:UInt8} and string_column = {phrase:String}"
```

<div id="tabs-in-url-parameters">
  ### URL 参数中的制表符
</div>

查询参数按 "escaped" 格式解析。这样做有一些好处，例如可以将 null 明确解析为 `\N`。这意味着制表符应编码为 `\t` (或 `\` 后跟一个制表符) 。例如，下面的内容在 `abc` 和 `123` 之间包含一个实际的制表符，因此输入字符串会被拆分为两个值：

```bash theme={null}
curl -sS "http://localhost:8123" -d "SELECT splitByChar('\t', 'abc      123')"
```

```response theme={null}
['abc','123']
```

不过，如果你尝试在 URL 参数中用 `%09` 对实际的制表符进行编码，就无法被正确解析：

```bash theme={null}
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`。例如：

```bash theme={null}
curl -sS "http://localhost:8123?param_arg1=abc%5C%09123" -d "SELECT splitByChar('\t', {arg1:String})"
```

```response theme={null}
['abc','123']
```

<div id="predefined_http_interface">
  ## 预定义 HTTP 接口
</div>

ClickHouse 支持通过 HTTP 接口执行特定查询。例如，您可以按如下方式将数据写入表中：

```bash theme={null}
$ echo '(4),(5),(6)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20VALUES' --data-binary @-
```

ClickHouse 还支持预定义 HTTP 接口，可帮助您更轻松地与 [Prometheus exporter](https://github.com/ClickHouse/clickhouse_exporter) 等第三方工具集成。下面来看一个示例。

首先，将以下部分添加到您的服务器配置文件中。

`http_handlers` 配置为包含多条 `rule`。ClickHouse 会将收到的 HTTP 请求与 `rule` 中预定义的类型进行匹配，首个匹配成功的规则会运行相应的处理程序。随后，如果匹配成功，ClickHouse 将执行对应的预定义查询。

```yaml title="config.xml" theme={null}
<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 格式的数据：

```bash theme={null}
$ 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` 完全符合 HTTP protocol 中 \[`method`]
  ([https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)) 的定义。这是一个可选配置。如果在
  配置文件中未定义，则不会匹配 HTTP 请求的方法部分。

* `url` 负责匹配 HTTP 请求中的 URL 部分 (path 和 query string) 。
  如果 `url` 带有 `regex:` 前缀，则使用 [RE2](https://github.com/google/re2) 的正则表达式。
  这是一个可选配置。如果在配置文件中未定义，则不会匹配 HTTP 请求的 URL 部分。

* `full_url` 与 `url` 相同，但包含完整 URL，即 `schema://host:port/path?query_string`。
  注意，ClickHouse 不支持“virtual hosts”，因此 `host` 是 IP 地址 (而不是 `Host` 请求头的值) 。

* `empty_query_string` - 确保请求中没有 query string (`?query_string`)

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

* `handler` 包含主要处理逻辑。

  它可以具有以下 `type`：

  * [`predefined_query_handler`](#predefined_query_handler)
  * [`dynamic_query_handler`](#dynamic_query_handler)
  * [`static`](#static)
  * [`redirect`](#redirect)

  以及以下参数：

  * `query` — 与 `predefined_query_handler` 类型一起使用，在调用处理程序时执行查询。
  * `query_param_name` — 与 `dynamic_query_handler` 类型一起使用，提取并执行 HTTP 请求参数中参数名为 `query_param_name` 的值。
  * `status` — 与 `static` 类型一起使用，表示响应状态码。
  * `content_type` — 可与任何类型一起使用，表示响应的 [content-type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)。
  * `http_response_headers` — 可与任何类型一起使用，表示响应请求头映射。也可用于设置 content type。
  * `response_content` — 与 `static` 类型一起使用，表示发送给客户端的响应内容；当使用前缀 'file://' 或 'config://' 时，会从文件或配置中查找内容并发送给客户端。
  * `user` - 用于执行查询的用户 (默认用户为 `default`) 。
    **注意**，无需为该用户指定密码。

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

<div id="predefined_query_handler">
  ### predefined\_query\_handler
</div>

`predefined_query_handler` 支持设置 `Settings` 和 `query_params` 的值。你可以在 `predefined_query_handler` 类型中配置 `query`。

`query` 的值是 `predefined_query_handler` 的预定义查询；当 HTTP 请求匹配时，ClickHouse 会执行该查询并返回查询结果。这是必填配置项。

以下示例定义了 [`max_threads`](/zh/reference/settings/session-settings#max_threads) 和 [`max_final_threads`](/zh/reference/settings/session-settings#max_final_threads) 这两个设置的值，然后查询系统表，以检查这些设置是否已成功生效。

<Note>
  要保留默认的 `handlers`，例如 `query`、`play`、`ping`，请添加 `<defaults/>` 规则。
</Note>

例如：

```yaml theme={null}
<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>
```

```bash theme={null}
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
```

<div id="virtual-param-request-body">
  #### 虚拟参数 `_request_body`
</div>

除了 URL 参数、请求头和查询参数外，`predefined_query_handler` 还支持一个特殊的虚拟参数 `_request_body`。
它以字符串形式包含原始 HTTP 请求体。
这样，你就可以创建灵活的 REST API，接受任意数据格式，并在查询中进行处理。

例如，你可以使用 `_request_body` 实现一个 REST 端点，在 POST 请求中接收 JSON 数据并将其插入表中：

```yaml theme={null}
<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>
```

随后，您可以将数据发送到此端点：

```bash theme={null}
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"}'
```

<Note>
  在一个 `predefined_query_handler` 中，只支持一个 `查询`。
</Note>

<div id="dynamic_query_handler">
  ### dynamic\_query\_handler
</div>

在 `dynamic_query_handler` 中，查询以 HTTP 请求参数的形式传入。不同的是，在 `predefined_query_handler` 中，查询写在配置文件里。`dynamic_query_handler` 中可以配置 `query_param_name`。

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

要试用此功能，下面的示例定义了 [`max_threads`](/zh/reference/settings/session-settings#max_threads) 和 `max_final_threads` 的值，并查询这些设置是否已成功生效。

示例：

```yaml theme={null}
<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>
```

```bash theme={null}
curl  -H 'XXX:TEST_HEADER_VALUE_DYNAMIC'  'http://localhost: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
```

<div id="static">
  ### static
</div>

`static` 可返回 [`content_type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type)、[status](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) 和 `response_content`。其中，`response_content` 用于返回指定的内容。

例如，要返回一条消息 "Say Hi!"：

```yaml highlight={14} theme={null}
<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`。

```yaml theme={null}
<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>
```

```bash theme={null}
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!%
```

查找配置发送给客户端的内容。

```yaml theme={null}
<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>
```

```bash theme={null}
$ 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>%
```

要查看从文件发送给客户端的内容：

```yaml theme={null}
<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>
```

```bash theme={null}
$ 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
```

<div id="redirect">
  ### redirect
</div>

`redirect` 会将请求以 `302` 重定向到 `location`

例如，下面展示了如何为 ClickHouse play 自动向 `play` 添加 set user：

```xml theme={null}
<clickhouse>
    <http_handlers>
        <rule>
            <methods>GET</methods>
            <url>/play</url>
            <handler>
                <type>redirect</type>
                <location>/play?user=play</location>
            </handler>
        </rule>
    </http_handlers>
</clickhouse>
```

<div id="http-response-headers">
  ## HTTP 响应头
</div>

ClickHouse 允许你配置自定义 HTTP 响应头，并将其应用于任何可配置的处理程序。这些响应头可通过 `http_response_headers` 设置，该设置接受表示请求头名称及其值的键值对。此功能特别适合在整个 ClickHouse HTTP 接口中实现自定义安全响应头、CORS 策略或任何其他 HTTP 请求头要求。

例如，你可以为以下对象配置响应头：

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

还可以指定 `common_http_response_headers`。这些响应头将应用于配置中定义的所有 HTTP 处理程序。

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

在下面的示例中，每个服务器响应都将包含两个自定义响应头：`X-My-Common-Header` 和 `X-My-Custom-Header`。

```xml theme={null}
<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>
```

<div id="valid-output-on-exception-http-streaming">
  ## HTTP 流式传输期间发生异常时的有效 JSON/XML 响应
</div>

通过 HTTP 执行查询时，如果部分数据已经发送，可能会发生异常。通常，异常会以纯文本形式发送给客户端。
即使数据输出时使用了特定格式，输出结果也可能因此不再是符合该格式的有效数据。
为避免这种情况，你可以使用设置 [`http_write_exception_in_output_format`](/zh/reference/settings/session-settings#http_write_exception_in_output_format) (默认禁用) ，该设置会指示 ClickHouse 以指定格式写出异常 (当前支持 XML 和 JSON\* 格式) 。

示例：

```bash theme={null}
$ 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)"
}
```

```bash theme={null}
$ 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>
```
