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

> 모든 플랫폼과 프로그래밍 언어에서 REST API를 통해 ClickHouse에 액세스할 수 있는 ClickHouse HTTP 인터페이스 문서

# HTTP 인터페이스

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

<div id="prerequisites">
  ## 사전 준비 사항
</div>

이 문서의 예시를 따라 하려면 다음이 필요합니다:

* 실행 중인 ClickHouse 서버 인스턴스
* `curl`이 설치되어 있어야 합니다. Ubuntu 또는 Debian에서는 `sudo apt install curl`을 실행하거나, 설치 방법은 이 [문서](https://curl.se/download.html)를 참조하십시오.

<div id="overview">
  ## 개요
</div>

HTTP 인터페이스를 사용하면 모든 플랫폼에서 모든 프로그래밍 언어를 통해 REST API 형태로 ClickHouse를 사용할 수 있습니다. HTTP 인터페이스는 네이티브 인터페이스보다 제약이 더 많지만, 더 다양한 언어를 지원합니다.

기본적으로 `clickhouse-server`는 다음 포트에서 수신 대기합니다:

* HTTP용 포트 8123
* HTTPS를 활성화하면 포트 8443

매개변수 없이 `GET /` 요청을 보내면 문자열 "Ok."와 함께 200 응답 코드가 반환됩니다:

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

"Ok."는 [`http_server_default_response`](/ko/reference/settings/server-settings/settings#http_server_default_response)에 정의된 기본값으로, 필요에 따라 변경할 수 있습니다.

참고: [HTTP 응답 코드 주의사항](#http_response_codes_caveats).

<div id="web-ui">
  ## 웹 사용자 인터페이스
</div>

ClickHouse에는 웹 사용자 인터페이스가 포함되어 있으며, 다음 주소에서 접속할 수 있습니다:

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

웹 UI는 쿼리 실행 중 진행 상황 표시, 쿼리 취소, 결과 스트리밍을 지원합니다.
또한 쿼리 파이프라인의 차트와 그래프를 표시하는 숨겨진 기능도 제공합니다.

쿼리가 성공적으로 실행되면 다운로드 버튼이 나타나며, 이를 통해 쿼리 결과를 CSV, TSV, JSON, JSONLines, Parquet, Markdown 또는 ClickHouse가 지원하는 사용자 지정 포맷 등 다양한 포맷으로 다운로드할 수 있습니다. 다운로드 기능은 쿼리 캐시를 사용해 쿼리를 다시 실행하지 않고도 결과를 효율적으로 가져옵니다. UI에 여러 페이지 중 한 페이지만 표시되었더라도 전체 결과를 다운로드합니다.

웹 UI는 전문가를 위해 설계되었습니다.

<Image img="https://mintcdn.com/private-7c7dfe99-fix-nav-issues/0xkAyEEn8ANRFZGQ/images/play.png?fit=max&auto=format&n=0xkAyEEn8ANRFZGQ&q=85&s=97f6421aa7522fe189176da17b9f7278" size="md" alt="ClickHouse 웹 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를 통해 쿼리하는 방법은 3가지입니다.

* 요청을 URL의 'query' 매개변수로 전송
* POST 메서드 사용
* 쿼리의 앞부분은 'query' 매개변수로 보내고, 나머지는 POST로 전송

<Note>
  URL 크기는 기본적으로 1 MiB로 제한되며, `http_max_uri_size` 설정으로 변경할 수 있습니다.
</Note>

성공하면 응답 코드 200과 함께 응답 본문에 결과가 반환됩니다.
오류가 발생하면 응답 코드 500과 함께 응답 본문에 오류 설명 텍스트가 반환됩니다.

GET을 사용하는 요청은 '읽기 전용'입니다. 즉, 데이터를 수정하는 쿼리에는 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`](/ko/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>

테이블(table)을 생성하려면:

```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 @-
```

어떤 데이터 포맷이든 지정할 수 있습니다. 예를 들어, `INSERT INTO t VALUES`를 작성할 때와 동일한 '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`](/ko/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`](/ko/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>

`database` URL 매개변수 또는 `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>

사용자 이름과 비밀번호는 다음 3가지 방법 중 하나로 지정할 수 있습니다.

1. HTTP 기본 인증을 사용하는 방법입니다.

예시:

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

2. `user` 및 `password` URL 매개변수에서

<Warning>
  매개변수가 웹 프록시에 기록되거나 브라우저에 캐시될 수 있으므로 이 메서드는 권장하지 않습니다
</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 매개변수를 사용해 단일 쿼리를 처리하기 위한 설정이나 설정 프로필 전체를 지정할 수 있습니다.

예시:

```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
```

자세한 내용은 다음 문서를 참조하십시오:

* [설정](/ko/reference/settings/session-settings)
* [SET](/ko/reference/statements/set)

<div id="using-clickhouse-sessions-in-the-http-protocol">
  ## HTTP 프로토콜에서 ClickHouse 세션 사용하기
</div>

HTTP 프로토콜에서도 ClickHouse 세션을 사용할 수 있습니다. 이렇게 하려면 요청에 `session_id` `GET` 매개변수를 추가해야 합니다. 세션 ID로는 임의의 문자열을 사용할 수 있습니다.

기본적으로 세션은 60초 동안 비활성 상태이면 종료됩니다. 이 timeout(초 단위)을 변경하려면 서버 구성에서 `default_session_timeout` 설정을 수정하거나 요청에 `session_timeout` `GET` 매개변수를 추가하십시오.

세션 상태를 확인하려면 `session_check=1` 매개변수를 사용하십시오. 하나의 세션에서는 한 번에 하나의 쿼리만 실행할 수 있습니다.

`X-ClickHouse-Progress` 응답 헤더에서 쿼리 진행 상태 정보를 받을 수 있습니다. 이렇게 하려면 [`send_progress_in_http_headers`](/ko/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"}
```

가능한 헤더 필드는 다음과 같습니다.

| Header field         | Description                                  |
| -------------------- | -------------------------------------------- |
| `read_rows`          | 읽은 행 수입니다.                                   |
| `read_bytes`         | 읽은 데이터의 바이트 단위 크기입니다.                        |
| `total_rows_to_read` | 읽을 전체 행 수입니다.                                |
| `written_rows`       | 기록한 행 수입니다.                                  |
| `written_bytes`      | 기록한 데이터의 바이트 단위 크기입니다.                       |
| `elapsed_ns`         | 쿼리의 나노초 단위 런타임입니다.                           |
| `memory_usage`       | 쿼리에서 사용한 메모리의 바이트 수입니다. (**v25.11부터 사용 가능**) |

실행 중인 요청은 HTTP connection이 끊겨도 자동으로 중단되지 않습니다. 구문 분석과 데이터 포맷팅은 server 측에서 수행되므로 네트워크 사용이 비효율적일 수 있습니다.

다음과 같은 선택적 매개변수가 있습니다.

| Parameters             | Description                                                                                                          |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `query_id` (optional)  | 쿼리 ID로 전달할 수 있습니다(임의의 문자열). [`replace_running_query`](/ko/reference/settings/session-settings#replace_running_query) |
| `quota_key` (optional) | 쿼터 키로 전달할 수 있습니다(임의의 문자열). ["쿼터"](/ko/concepts/features/configuration/server-config/quotas)                          |

HTTP 인터페이스에서는 쿼리를 위해 외부 데이터(외부 임시 테이블)를 전달할 수 있습니다. 자세한 내용은 ["쿼리 처리용 외부 데이터"](/ko/reference/engines/table-engines/special/external-data)를 참조하십시오.

<div id="response-buffering">
  ## 응답 버퍼링
</div>

응답 버퍼링은 서버 측에서 활성화할 수 있습니다. 이를 위해 다음 URL 매개변수를 사용할 수 있습니다.

* `buffer_size`
* `wait_end_of_query`

다음 설정도 사용할 수 있습니다.

* [`http_response_buffer_size`](/ko/reference/settings/session-settings#http_response_buffer_size)
* [`http_wait_end_of_query`](/ko/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 headers가 클라이언트에 전송된 뒤 쿼리 처리 오류가 발생하는 상황을 방지하려면 버퍼링을 사용하십시오. 이런 경우 오류 메시지는 응답 본문 끝에 기록되며, 클라이언트 측에서는 파싱 단계에서만 오류를 감지할 수 있습니다.
</Tip>

<div id="setting-role-with-query-parameters">
  ## 쿼리 매개변수로 역할 설정
</div>

이 기능은 ClickHouse 24.4에 추가되었습니다.

특정한 상황에서는 SQL 문 자체를 실행하기 전에 먼저 부여된 역할을 설정해야 할 수 있습니다.
하지만 다중 SQL 문은 허용되지 않으므로 `SET ROLE`과 SQL 문을 함께 전송할 수 없습니다.

```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;"
```

이는 SQL 문을 실행하기 전에 `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`는 해당 SQL 문을 실행하기 전에 `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 헤더가 먼저 HTTP 코드 200과 함께 전송되고, 그다음 HTTP 본문이 전송되며, 이후 오류가 일반 텍스트로 본문에 삽입됩니다.

이 동작은 사용한 포맷과 무관하며, `Native`, `TSV`, `JSON` 중 어떤 것을 사용하든 오류 메시지는 항상 응답 스트림의 중간에 나타납니다.

이 문제는 `wait_end_of_query=1`([응답 버퍼링](#response-buffering))을 활성화하여 완화할 수 있습니다. 이 경우 전체 쿼리 처리가 끝날 때까지 HTTP 헤더 전송이 지연됩니다. 하지만 이렇게 해도 문제가 완전히 해결되지는 않습니다. 결과는 여전히 [`http_response_buffer_size`](/ko/reference/settings/session-settings#http_response_buffer_size) 안에 들어가야 하며, [`send_progress_in_http_headers`](/ko/reference/settings/session-settings#send_progress_in_http_headers) 같은 다른 설정이 헤더 전송 지연에 영향을 줄 수 있기 때문입니다.

<Tip>
  모든 오류를 포착하는 유일한 방법은 필요한 포맷으로 파싱하기 전에 HTTP 본문을 분석하는 것입니다.
</Tip>

ClickHouse에서 이러한 예외는 `http_write_exception_in_output_format=0`(기본값)일 때 사용한 포맷(`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용 매개변수가 있는 쿼리](/ko/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" 포맷에서 파싱됩니다. 이 방식에는 `\N`을 NULL로 명확하게 파싱할 수 있다는 점 등 몇 가지 장점이 있습니다. 즉, 탭 문자는 `\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는 [Prometheus exporter](https://github.com/ClickHouse/clickhouse_exporter)와 같은 서드파티 도구와 더 쉽게 통합할 수 있도록 Predefined HTTP Interface도 지원합니다. 예시를 살펴보겠습니다.

먼저 서버 설정 파일에 이 섹션을 추가하십시오.

`http_handlers`는 여러 개의 `rule`을 포함하도록 구성됩니다. ClickHouse는 수신한 HTTP 요청을 `rule`에 미리 정의된 유형과 일치시키고, 가장 먼저 일치한 규칙의 핸들러를 실행합니다. 그런 다음 일치에 성공하면 해당하는 미리 정의된 쿼리를 실행합니다.

```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" "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://developer.mozilla.org/en-US/docs/Web/HTTP/Methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)) 정의를 완전히 따릅니다. 이는 선택적 구성입니다. 설정 파일에 정의하지 않으면
  HTTP 요청의 메서드 부분은 매칭하지 않습니다.

* `url`은 HTTP 요청의 URL 부분(경로 및 쿼리 문자열)을 매칭합니다.
  `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` header의 값이 아닙니다.

* `empty_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`](/ko/reference/settings/session-settings#max_threads) 및 [`max_final_threads`](/ko/reference/settings/session-settings#max_final_threads) 설정 값을 지정한 다음, 시스템 테이블(system table)을 쿼리하여 이러한 설정이 성공적으로 적용되었는지 확인합니다.

<Note>
  `query`, `play`, `ping`과 같은 기본 `handlers`를 유지하려면 `<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>

`predefined_query_handler`는 URL 매개변수, 헤더, 쿼리 매개변수 외에도 특수한 가상 매개변수 `_request_body`를 지원합니다.
이 매개변수에는 원시 HTTP 요청 본문이 문자열로 포함됩니다.
이를 통해 임의의 데이터 포맷을 받아 쿼리 내에서 처리할 수 있는 유연한 REST API를 만들 수 있습니다.

예를 들어, `_request_body`를 사용하면 POST 요청으로 JSON 데이터를 받아 테이블에 삽입하는 REST 엔드포인트를 구현할 수 있습니다:

```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` 하나당 지원되는 `query`는 하나뿐입니다.
</Note>

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

`dynamic_query_handler`에서는 HTTP 요청의 매개변수 형식으로 쿼리를 작성합니다. `predefined_query_handler`와의 차이점은 `predefined_query_handler`에서는 쿼리를 설정 파일에 작성한다는 것입니다. `query_param_name`은 `dynamic_query_handler`에서 구성할 수 있습니다.

ClickHouse는 HTTP 요청 URL에서 `query_param_name`에 해당하는 값을 추출해 실행합니다. `query_param_name`의 기본값은 `/query`입니다. 이는 선택적 구성입니다. 설정 파일에 정의되어 있지 않으면 이 매개변수는 전달되지 않습니다.

이 기능을 시험해 보기 위해, 다음 예시에서는 [`max_threads`](/ko/reference/settings/session-settings#max_threads)와 `max_final_threads` 값을 정의하고, 설정이 올바르게 적용되었는지 `queries`로 확인합니다.

예시:

```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`는 `location`으로 `302` 리디렉션을 수행합니다.

예를 들어 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 응답 헤더를 설정할 수 있습니다. 이러한 헤더는 헤더 이름과 해당 값을 나타내는 key-value 쌍을 받는 `http_response_headers` 설정으로 지정할 수 있습니다. 이 기능은 ClickHouse HTTP 인터페이스 전반에서 사용자 지정 보안 헤더, CORS 정책 또는 기타 HTTP 헤더 요구 사항을 구현할 때 특히 유용합니다.

예를 들어, 다음에 대한 헤더를 구성할 수 있습니다.

* 일반 쿼리 엔드포인트
* 웹 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 streaming 중 예외 발생 시 유효한 JSON/XML 응답
</div>

HTTP를 통해 쿼리를 실행하는 동안 데이터의 일부가 이미 전송된 후 예외가 발생할 수 있습니다. 일반적으로 예외는 일반 텍스트로 클라이언트에 전송됩니다.
데이터를 출력할 때 특정 데이터 포맷을 사용했더라도, 그 결과가 지정된 데이터 포맷 기준으로는 유효하지 않게 될 수 있습니다.
이를 방지하려면 [`http_write_exception_in_output_format`](/ko/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>
```
