HTTP 인터페이스
HTTP 인터페이스 (HTTP interface)
HTTP 인터페이스는 ClickHouse를 REST API 형태로 어떤 플랫폼에서든 어떤 프로그래밍 언어로든 사용할 수 있게 해 줘요. 네이티브 인터페이스보다는 제한적이지만 언어 지원이 더 좋아요.
출처: 문서
본문
사전 준비 (Prerequisites)
이 문서의 예시를 위해서는 다음이 필요해요:
- 실행 중인 ClickHouse 서버 인스턴스
curl설치. Ubuntu 또는 Debian에서sudo apt install curl을 실행하거나 이 문서를 참고해 설치 지침을 확인하세요.
개요 (Overview)
HTTP 인터페이스는 REST API 형태로 어떤 플랫폼에서든 어떤 프로그래밍 언어로든 ClickHouse를 사용할 수 있게 해 줘요. HTTP 인터페이스는 네이티브 인터페이스보다 제한적이지만 언어 지원이 더 좋아요.
기본적으로 clickhouse-server는 다음 포트를 듣습니다:
- HTTP용 8123 포트
- HTTPS용 8443 포트 활성화 가능
파라미터 없이 GET / 요청을 하면 200 응답 코드와 함께 문자열 "Ok."이 반환돼요:
$ curl 'http://localhost:8123/'
Ok.
"Ok."는 http_server_default_response에 정의된 기본값이며 원하면 변경할 수 있어요.
또한 참고: HTTP 응답 코드 주의 사항.
웹 사용자 인터페이스 (Web user interface)
ClickHouse는 다음 주소에서 접근할 수 있는 웹 사용자 인터페이스를 포함해요:
http://localhost:8123/play
웹 UI는 쿼리 실행 중 진행 표시, 쿼리 취소, 결과 스트리밍을 지원해요. 쿼리 파이프라인을 위한 차트와 그래프를 표시하는 비밀 기능도 있어요.
쿼리가 성공적으로 실행된 후 다운로드 버튼이 나타나며, CSV, TSV, JSON, JSONLines, Parquet, Markdown 또는 ClickHouse가 지원하는 어떤 사용자 정의 포맷으로든 쿼리 결과를 다운로드할 수 있어요. 다운로드 기능은 쿼리 캐시를 사용해 쿼리를 재실행하지 않고 효율적으로 결과를 가져와요. UI가 여러 페이지 중 한 페이지만 표시했더라도 전체 결과 세트를 다운로드해요.
웹 UI는 여러분 같은 전문가를 위해 설계됐어요.
헬스 체크 스크립트에서는 GET /ping 요청을 사용하세요. 이 핸들러는 항상 "Ok."을 반환해요(끝에 줄바꿈 포함). 버전 18.12.13부터 사용 가능. 복제본 지연을 확인하려면 /replicas_status도 참고하세요.
$ curl 'http://localhost:8123/ping'
Ok.
$ curl 'http://localhost:8123/replicas_status'
Ok.
HTTP/HTTPS로 쿼리하기 (Querying over HTTP/HTTPS)
HTTP/HTTPS로 쿼리하는 방법은 세 가지가 있어요:
- URL 'query' 파라미터로 요청 보내기
- POST 메서드 사용.
- 'query' 파라미터에 쿼리 시작 부분을 보내고 나머지는 POST로 보내기
참고: URL의 크기는 기본적으로 1MiB로 제한되며, http_max_uri_size 설정으로 변경할 수 있어요.
성공하면 200 응답 코드와 함께 응답 본문에 결과를 받아요. 오류가 발생하면 500 응답 코드와 함께 응답 본문에 오류 설명 텍스트를 받아요.
GET을 사용한 요청은 'readonly'예요. 즉 데이터를 수정하는 쿼리에는 POST 메서드만 사용할 수 있어요. 쿼리 자체는 POST 본문이나 URL 파라미터에 보낼 수 있어요. 몇 가지 예를 살펴볼게요.
아래 예시에서 curl은 SELECT 1 쿼리를 보내는 데 사용돼요. 공백에 URL 인코딩 %20이 사용된 것에 주목하세요.
curl 'http://localhost:8123/?query=SELECT%201'
1
이 예시에서 wget은 결과를 터미널에 출력하기 위해 -nv(non-verbose)와 -O- 파라미터와 함께 사용돼요.
이 경우 공백에 URL 인코딩을 사용할 필요가 없어요:
wget -nv -O- 'http://localhost:8123/?query=SELECT 1'
1
이 예시에서는 raw 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 'http://localhost:8123/' --data-binary @-
1
$ echo 'SELECT 1' | curl 'http://localhost:8123/?query=' --data-binary @-
1
$ echo '1' | curl 'http://localhost:8123/?query=SELECT' --data-binary @-
1
쿼리의 일부가 파라미터로, 일부가 POST로 보내지면 이 두 데이터 부분 사이에 줄바꿈이 삽입돼요. 예를 들어 이것은 동작하지 않아요:
$ echo 'ECT 1' | curl 'http://localhost:8123/?query=SEL' --data-binary @-
Code: 59, e.displayText() = DB::Exception: Syntax error: failed at position 0: SEL
ECT 1
, expected One of: SHOW TABLES, SHOW DATABASES, SELECT, INSERT, CREATE, ATTACH, RENAME, DROP, DETACH, USE, SET, OPTIMIZE., e.what() = DB::Exception
기본적으로 데이터는 TabSeparated 포맷으로 반환돼요.
다른 포맷을 요청하려면 쿼리에서 FORMAT 절을 사용해요. 예를 들어:
wget -nv -O- 'http://localhost:8123/?query=SELECT 1, 2, 3 FORMAT JSON'
{
"meta":
[
{
"name": "1",
"type": "UInt8"
},
{
"name": "2",
"type": "UInt8"
},
{
"name": "3",
"type": "UInt8"
}
],
"data":
[
{
"1": 1,
"2": 2,
"3": 3
}
],
"rows": 1,
"statistics":
{
"elapsed": 0.000515,
"rows_read": 1,
"bytes_read": 1
}
}
TabSeparated 외의 기본 포맷을 지정하려면 default_format URL 파라미터를 사용할 수 있어요. X-ClickHouse-Format 헤더는 응답의 포맷을 명시적으로 선택해요. 이는 output_format 설정의 별칭이므로 쿼리의 FORMAT 절도 재정의해요. INSERT의 요청 본문이 어떻게 파싱되는지는 절대 바꾸지 않아요. 그 용도는 input_format 또는 format을 사용하세요.
$ echo 'SELECT 1 FORMAT Pretty' | curl 'http://localhost:8123/?' --data-binary @-
┏━━━┓
┃ 1 ┃
┡━━━┩
│ 1 │
└───┘
POST 메서드를 파라미터화된 쿼리와 함께 사용할 수 있어요. 파라미터는 이름과 타입과 함께 {name:Type}처럼 중괄호로 지정돼요. 파라미터 값은 param_name으로 전달돼요:
$ curl -X POST -F 'query=select {p1:UInt8} + {p2:UInt8}' -F "param_p1=3" -F "param_p2=4" 'http://localhost:8123/'
7
URL 경로로 테이블 접근 및 쿼리 구성 (Access tables through URL paths and construct queries)
ClickHouse 26.8 이상에서 사용 가능.
HTTP 인터페이스는 URL 경로를 데이터베이스, 테이블, 출력 포맷, 압축 방법으로 해석할 수 있어요. URL 파라미터가 결과를 만들 수 있으므로, 간단한 읽기 요청은 SQL이 필요 없어요. 이 기능들은 기본적으로 비활성화되어 있으며 명시적으로 활성화해야 해요.
경로 라우팅 활성화 (Enable path routing)
경로 해석은 두 수준에서 게이팅돼요:
- HTTP 인터페이스가 경로 스타일 요청을 쿼리 핸들러로 라우팅할 수 있게 하는 서버 레벨
http_allow_path_requests구성 설정을 활성화:
<clickhouse>
<http_allow_path_requests>1</http_allow_path_requests>
</clickhouse>
- 필요한 사용자별 설정을 활성화:
| 설정 | 효과 |
|---|---|
http_allow_table_as_file |
마지막 경로 구성 요소를 table, table.format 또는 table.format.compression으로 해석. |
http_allow_database_as_path |
선행 /database/ 경로 구성 요소를 현재 데이터베이스로 해석. |
http_allow_filters_as_path |
Hive 스타일 /name=value/ 경로 구성 요소를 WHERE 필터로 해석. |
http_allow_filters_as_unrecognized_url_parameters |
인식되지 않은 URL 파라미터를 WHERE 필터로 해석. |
참고: 라우팅은 인증 전에 발생하므로 사용자별 설정에 의존할 수 없어요. http_allow_path_requests가 비활성화되면 알 수 없는 경로는 인증 전 404를 반환해요. 라우팅과 인증 후에는 사용자별 설정이 경로가 어떻게 해석되는지 결정하므로, 사용자, 역할 또는 프로필에 대해 선택적으로 기능을 활성화할 수 있어요.
테이블을 파일로 접근 (Access tables as files)
http_allow_table_as_file이 활성화되면 /table.format.compression에 대한 요청이 SELECT * FROM table로 처리돼요. /database/table.format.compression을 사용하려면 http_allow_database_as_path를 활성화하세요.
# SELECT * FROM my_db.hits, formatted as CSV
curl 'http://localhost:8123/my_db/hits.csv'
# The same result, compressed with gzip
curl 'http://localhost:8123/my_db/hits.csv.gz' | gzip -d
포맷과 압축 확장자는 대소문자를 구분하지 않고 인식되므로 hits.csv와 hits.CSV는 동등해요.
명시적 format 또는 output_format URL 파라미터는 경로의 포맷을 재정의해요. default_format는 그렇지 않아요. 다른 어떤 것도 포맷을 선택하지 않을 때 사용할 포맷만 제공하며, 경로 확장자가 더 구체적이에요. 명시적 compression 파라미터는 경로의 압축과 일치해야 해요. 충돌하는 값은 예외가 발생해요.
쿼리 구성 (Construct a query)
다음 설정은 기본 쿼리를 파생 테이블로 감싸요. 그것들은 서로 및 기존 쿼리와 구성돼요. HTTP URL 파라미터로, 쿼리 내 SETTINGS 절로, 또는 사용자 프로필을 통해 제공할 수 있어요.
| 설정 | 효과 |
|---|---|
select |
SELECT <expression_list> FROM (…) |
filter |
WHERE <expression> 추가. 여러 filter URL 파라미터는 AND로 결합. |
order |
ORDER BY <expression_list> 추가. |
sort |
식별자나 열 위치의 쉼표 구분 목록에서 ORDER BY 추가. 각각 선택적 +(오름차순) 또는 -(내림차순) 접두사 사용, 예: sort=a,-b. order와 결합할 수 없음. |
limit 및 offset |
LIMIT <n> OFFSET <m> 추가. 둘 다 꼬리 선택을 위한 음수 값과 행의 비율을 나타내는 분수 값을 받아들임. |
page |
offset = limit * (page - 1) 설정. limit이 필요하며 offset와 결합할 수 없음. |
# Filter my_db.hits, sort by a descending, and return the first 10 rows
curl 'http://localhost:8123/my_db/hits?filter=a%3E0&sort=-a&limit=10'
# Return the second page of 100 rows
curl 'http://localhost:8123/my_db/hits?limit=100&page=2'
기존 쿼리 수정 (Modify an existing query)
구성 설정은 경로 요청에만 국한되지 않아요. 직접 작성한 쿼리도 만들 수 있어요. 쿼리는 파생 테이블이 되므로 설정은 그 안에 병합되는 것이 아니라 그 결과에 적용돼요. 예를 들어 ?query=SELECT a, b FROM hits&filter=a > 0&sort=-b&limit=10은 이렇게 실행돼요:
SELECT * FROM (SELECT a, b FROM hits) WHERE a > 0 ORDER BY b DESC LIMIT 10
이것은 다른 곳에 고정된 쿼리 — 저장된 대시보드 쿼리, predefined_query_handler, URL 파라미터만 추가할 수 있는 클라이언트 — 의 결과를 페이지로 나누거나, 정렬하거나, 좁히는 데 유용해요:
# Page through the result of an arbitrary query without editing the query text
curl 'http://localhost:8123/?query=SELECT+a,+b+FROM+hits+GROUP+BY+a,+b&limit=100&page=3'
# Keep only some of the resulting columns and rows
curl -G 'http://localhost:8123/' --data-urlencode 'query=SELECT * FROM hits' --data-urlencode 'select=a, b' --data-urlencode 'filter=b != 0'
# The last 5 rows of an aggregate (a negative `limit` selects from the tail)
curl 'http://localhost:8123/?query=SELECT+a,+count()+FROM+hits+GROUP+BY+a+ORDER+BY+a&limit=-5'
설정이 쿼리를 다시 쓰는 대신 감싸므로, FORMAT 절과 쿼리 내 ORDER BY와 구성되며 INSERT가 쓰는 행을 절대 바꾸지 않아요. INSERT ... SELECT 문에 놓인 구성 설정은 문 자신의 (빈) 결과를 만들지, 그 소스 SELECT를 만들지 않아요. 소스를 만들려면 설정을 SELECT 자신의 SETTINGS 절에 넣으세요:
-- Inserts all 10 rows: `limit` applies to the INSERT statement, not to its SELECT
INSERT INTO t SETTINGS limit = 2 SELECT number FROM numbers(10);
-- Inserts 2 rows: `limit` applies to the SELECT itself
INSERT INTO t SELECT number FROM numbers(10) SETTINGS limit = 2;
경고: filter는 접근 제어 메커니즘이 아니에요. 그것은 래핑 하위 쿼리 위에 WHERE 절을 추가하므로, 필터가 적용되기 전에 기본 데이터를 읽고 처리할 수 있어요. 사용자가 접근할 수 있는 행을 제한하려면 행 정책(row policies) 또는 additional_table_filters를 사용하세요.
포맷 및 압축 재정의 (Override formats and compression)
| 설정 | 효과 |
|---|---|
output_format |
출력 포맷을 재정의. 쿼리의 FORMAT 절, 경로 확장자, format, default_format보다 우선. X-ClickHouse-Format 헤더로도 설정 가능. |
input_format |
INSERT의 입력 포맷을 재정의. 쿼리의 FORMAT 절과 format보다 우선. |
format |
방향별 설정이 제공되지 않는 한 양방향으로 포맷 재정의. |
default_format |
쿼리에 FORMAT 절, 경로 확장자, 다른 포맷 재정의가 없을 때 출력 포맷을 설정. |
compression |
응답 본문을 압축, 예: compression=gz. HTTP Content-Encoding 및 ClickHouse 네이티브 compress 파라미터와 독립적. |
포맷 설정은 네이티브 클라이언트와 clickhouse-local을 포함한 다른 프로토콜에서도 작동해요. input_format과 output_format은 --input-format과 --output-format 옵션에 해당해요. --format 옵션은 clickhouse-local에서는 양방향 format 설정에 매핑되고, clickhouse-client에서는 역사적 출력 전용 의미를 유지하며 output_format에 매핑돼요.
compression은 HTTP 응답 형성에 한정되며 쿼리 실행 전에 소비돼요. HTTP URL 파라미터, 경로 확장자 또는 사용자 프로필로 제공하세요. 쿼리 내 SETTINGS 절에서는 거부돼요.
바이너리 및 압축된 HTTP 응답에는 Content-Disposition: attachment; filename=… 헤더가 포함돼요. 파일 이름은 URL 경로에서 파생되거나, 경로가 제공하지 않을 때 result.<format>.<compression>을 사용해요.
경로 테이블을 쿼리와 함께 사용 (Use a path table with a query)
경로가 테이블을 식별하고 query 파라미터도 제공하면, 경로 테이블은 implicit_table_at_top_level을 통해 노출돼요. FROM 절이 없는 SELECT는 경로 테이블에서 읽어요:
# Read columns a and b from my_db.hits without a FROM clause
curl 'http://localhost:8123/my_db/hits.CSV?query=SELECT+a,+b'
쿼리에 이미 FROM 절이 있으면 경로 구성 요소는 다운로드 파일 이름만 제공해요.
HTTP/HTTPS를 통한 INSERT 쿼리 (Insert queries over HTTP/HTTPS)
INSERT 쿼리에는 데이터를 전송하는 POST 메서드가 필요해요. 이 경우 URL 파라미터에 쿼리 시작 부분을 쓰고 POST로 삽입할 데이터를 전달할 수 있어요. 삽입할 데이터는 예를 들어 MySQL의 탭으로 구분된 덤프일 수 있어요. 이렇게 INSERT 쿼리는 MySQL의 LOAD DATA LOCAL INFILE을 대체해요.
예시 (Examples)
테이블을 만들려면:
$ echo 'CREATE TABLE t (a UInt8) ENGINE = Memory' | curl 'http://localhost:8123/' --data-binary @-
익숙한 INSERT 쿼리로 데이터 삽입에 사용하려면:
$ echo 'INSERT INTO t VALUES (1),(2),(3)' | curl 'http://localhost:8123/' --data-binary @-
쿼리와 별도로 데이터를 보내려면:
$ echo '(4),(5),(6)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20VALUES' --data-binary @-
어떤 데이터 포맷이든 지정할 수 있어요. 예를 들어 INSERT INTO t VALUES를 쓸 때 사용되는 것과 같은 'Values' 포맷을 지정할 수 있어요:
$ echo '(7),(8),(9)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20FORMAT%20Values' --data-binary @-
탭으로 구분된 덤프에서 데이터를 삽입하려면 해당 포맷을 지정해요:
$ echo -ne '10\n11\n12\n' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20FORMAT%20TabSeparated' --data-binary @-
테이블 내용을 읽으려면:
$ curl 'http://localhost:8123/?query=SELECT%20a%20FROM%20t'
7
8
9
10
11
12
1
2
3
4
5
6
참고: 병렬 쿼리 처리로 인해 데이터는 임의의 순서로 출력돼요.
테이블을 삭제하려면:
$ echo 'DROP TABLE t' | curl 'http://localhost:8123/' --data-binary @-
데이터 테이블을 반환하지 않는 성공적인 요청에는 빈 응답 본문이 반환돼요.
압축 (Compression)
압축은 많은 양의 데이터를 전송할 때 네트워크 트래픽을 줄이거나, 즉시 압축된 덤프를 만드는 데 사용할 수 있어요.
데이터 전송 시 ClickHouse 내부 압축 포맷을 사용할 수 있어요. 압축된 데이터는 비표준 포맷이며, 그것을 다루려면 clickhouse-compressor 프로그램이 필요해요. clickhouse-client 패키지와 함께 기본 설치돼요.
데이터 삽입의 효율을 높이려면 http_native_compression_disable_checksumming_on_decompress 설정을 사용해 서버 측 체크섬 검증을 비활성화하세요.
URL에 compress=1을 지정하면 서버가 보내는 데이터를 압축해요. URL에 decompress=1을 지정하면 서버가 POST 메서드로 전달하는 데이터를 압축 해제해요.
HTTP 압축을 선택할 수도 있어요. ClickHouse는 다음 압축 방법을 지원해요:
gzipbrdeflatexzzstdlz4bz2snappy
압축된 POST 요청을 보내려면 요청 헤더 Content-Encoding: compression_method를 추가하세요.
ClickHouse가 응답을 압축하게 하려면 요청에 Accept-Encoding: compression_method 헤더를 추가하세요.
모든 압축 방법에 대해 http_zlib_compression_level 설정으로 데이터 압축 수준을 구성할 수 있어요.
정보: 일부 HTTP 클라이언트는 기본적으로 서버의 데이터를 압축 해제할 수 있으므로(gzip 및 deflate) 압축 설정을 올바르게 사용해도 압축 해제된 데이터를 받을 수 있어요.
예시 (Examples)
서버에 압축된 데이터를 보내려면:
echo "SELECT 1" | gzip -c | \
curl -sS --data-binary @- -H 'Content-Encoding: gzip' 'http://localhost:8123/'
서버에서 압축된 데이터 아카이브를 받으려면:
curl -vsS "http://localhost:8123/?enable_http_compression=1" \
-H 'Accept-Encoding: gzip' --output result.gz -d 'SELECT number FROM system.numbers LIMIT 3'
zcat result.gz
0
1
2
gunzip으로 압축 해제된 데이터를 받으려면:
curl -sS "http://localhost:8123/?enable_http_compression=1" \
-H 'Accept-Encoding: gzip' -d 'SELECT number FROM system.numbers LIMIT 3' | gunzip -
0
1
2
기본 데이터베이스 (Default database)
database URL 파라미터나 X-ClickHouse-Database 헤더로 기본 데이터베이스를 지정할 수 있어요.
echo 'SELECT number FROM numbers LIMIT 10' | curl 'http://localhost:8123/?database=system' --data-binary @-
0
1
2
3
4
5
6
7
8
9
기본적으로 서버 설정에 등록된 데이터베이스가 기본 데이터베이스로 사용돼요. 즉시 사용 가능한 상태에서는 default라는 데이터베이스예요. 또는 테이블 이름 앞에 점을 사용해 항상 데이터베이스를 지정할 수 있어요.
인증 (Authentication)
사용자 이름과 비밀번호는 세 가지 방법 중 하나로 표시할 수 있어요:
- HTTP 기본 인증(Basic Authentication) 사용.
예를 들어:
echo 'SELECT 1' | curl 'http://user:password@localhost:8123/' -d @-
user와passwordURL 파라미터에
경고: 파라미터가 웹 프록시에 기록되고 브라우저에 캐시될 수 있으므로 이 방법을 권장하지 않아요.
예를 들어:
echo 'SELECT 1' | curl 'http://localhost:8123/?user=user&password=password' -d @-
- 'X-ClickHouse-User'와 'X-ClickHouse-Key' 헤더 사용
예를 들어:
echo 'SELECT 1' | curl -H 'X-ClickHouse-User: user' -H 'X-ClickHouse-Key: password' 'http://localhost:8123/' -d @-
사용자 이름이 지정되지 않으면 default 이름이 사용돼요. 비밀번호가 지정되지 않으면 빈 비밀번호가 사용돼요.
URL 파라미터로 단일 쿼리 또는 전체 설정 프로필을 처리하기 위한 설정을 지정할 수도 있어요.
예를 들어:
http://localhost:8123/?profile=web&max_rows_to_read=1000000000&query=SELECT+1
$ echo 'SELECT number FROM system.numbers LIMIT 10' | curl 'http://localhost:8123/?' --data-binary @-
0
1
2
3
4
5
6
7
8
9
자세한 내용은 다음을 참고해요:
HTTP 프로토콜에서 ClickHouse 세션 사용 (Using ClickHouse sessions in the HTTP protocol)
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 인터페이스는 쿼리용 외부 데이터(외부 임시 테이블) 전달을 허용해요. 자세한 내용은 "쿼리 처리를 위한 외부 데이터"를 참고해요.
응답 버퍼링 (Response buffering)
응답 버퍼링은 서버 측에서 활성화할 수 있어요. 이를 위해 다음 URL 파라미터가 제공돼요:
buffer_sizewait_end_of_query
다음 설정을 사용할 수 있어요:
buffer_size는 서버 메모리에 버퍼링할 결과의 바이트 수를 결정해요. 결과 본문이 이 임계값보다 크면 버퍼가 HTTP 채널에 쓰여지고 나머지 데이터는 HTTP 채널로 직접 전송돼요.
전체 응답이 버퍼링되도록 하려면 wait_end_of_query=1을 설정하세요. 이 경우 메모리에 저장되지 않은 데이터는 임시 서버 파일에 버퍼링돼요.
예를 들어:
curl -sS 'http://localhost:8123/?max_result_bytes=4000000&buffer_size=3000000&wait_end_of_query=1' -d 'SELECT toUInt8(number) FROM system.numbers LIMIT 9000000 FORMAT RowBinary'
팁: 응답 코드와 HTTP 헤더가 클라이언트에 전송된 후 쿼리 처리 오류가 발생하는 상황을 피하려면 버퍼링을 사용하세요. 이 상황에서 오류 메시지가 응답 본문 끝에 쓰여지고, 클라이언트 측에서는 파싱 단계에서만 오류를 감지할 수 있어요.
쿼리 파라미터로 역할 설정 (Setting a role with query parameters)
이 기능은 ClickHouse 24.4에서 추가됐어요.
특정 시나리오에서는 문 자체를 실행하기 전에 먼저 부여된 역할을 설정해야 할 수 있어요.
하지만 다중 문이 허용되지 않으므로 SET ROLE과 문을 함께 보낼 수 없어요:
curl -sS "http://localhost:8123" --data-binary "SET ROLE my_role;SELECT * FROM my_table;"
위 명령은 오류를 발생시켜요:
Code: 62. DB::Exception: Syntax error (Multi-statements are not allowed)
이 제한을 극복하려면 대신 role 쿼리 파라미터를 사용하세요:
curl -sS "http://localhost:8123?role=my_role" --data-binary "SELECT * FROM my_table;"
이것은 문 전에 SET ROLE my_role을 실행하는 것과 동일해요.
또한 여러 role 쿼리 파라미터를 지정할 수 있어요:
curl -sS "http://localhost:8123?role=my_role&role=my_other_role" --data-binary "SELECT * FROM my_table;"
이 경우 ?role=my_role&role=my_other_role은 문 전에 SET ROLE my_role, my_other_role을 실행하는 것과 비슷하게 동작해요.
HTTP 응답 코드 주의 사항 (HTTP response codes caveats)
HTTP 프로토콜의 제한 때문에 HTTP 200 응답 코드가 쿼리가 성공했음을 보장하지 않아요.
예시:
curl -v -Ss "http://localhost:8123/?max_block_size=1&query=select+sleepEachRow(0.001),throwIf(number=2)from+numbers(5)"
* Trying 127.0.0.1:8123...
...
< HTTP/1.1 200 OK
...
Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(equals(number, 2) :: 1) -> throwIf(equals(number, 2))
이 동작의 이유는 HTTP 프로토콜의 특성 때문이에요. HTTP 헤더가 HTTP 코드 200으로 먼저 전송되고, 그 다음 HTTP 본문이 오고, 그 다음 오류가 평문 텍스트로 본문에 주입돼요.
이 동작은 사용된 포맷이 Native, TSV, JSON 중 무엇이든 무관해요. 오류 메시지는 항상 응답 스트림 중간에 있어요.
wait_end_of_query=1(응답 버퍼링)을 활성화하면 이 문제를 완화할 수 있어요. 이 경우 HTTP 헤더 전송이 전체 쿼리가 해결될 때까지 지연돼요. 하지만 이는 결과가 여전히 http_response_buffer_size에 들어맞아야 하고, send_progress_in_http_headers 같은 다른 설정이 헤더 지연을 방해할 수 있으므로 문제를 완전히 해결하지는 못해요.
팁: 모든 오류를 잡는 유일한 방법은 필요 포맷으로 파싱하기 전에 HTTP 본문을 분석하는 것이에요.
ClickHouse의 이러한 예외는 http_write_exception_in_output_format=0(기본값)일 때 사용된 포맷(예: Native, TSV, JSON 등)과 무관하게 아래와 같이 일관된 예외 포맷을 가져요. 이렇게 하면 클라이언트 측에서 오류 메시지를 쉽게 파싱하고 추출할 수 있어요.
\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>에서 찾을 수 있음). 위에 설명된 전체 예외 블록은 최대 16KiB까지 될 수 있어요.
JSON 포맷의 예시:
$ curl -v -Ss "http://localhost:8123/?max_block_size=1&query=select+sleepEachRow(0.001),throwIf(number=2)from+numbers(5)+FORMAT+JSON"
...
{
"meta":
[
{
"name": "sleepEachRow(0.001)",
"type": "UInt8"
},
{
"name": "throwIf(equals(number, 2))",
"type": "UInt8"
}
],
"data":
[
{
"sleepEachRow(0.001)": 0,
"throwIf(equals(number, 2))": 0
},
{
"sleepEachRow(0.001)": 0,
"throwIf(equals(number, 2))": 0
}
__exception__
dmrdfnujjqvszhav
Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(equals(__table1.number, 2_UInt8) :: 1) -> throwIf(equals(__table1.number, 2_UInt8)) UInt8 : 0'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 25.11.1.1)
262 dmrdfnujjqvszhav
__exception__
CSV 포맷의 유사한 예시:
$ curl -v -Ss "http://localhost:8123/?max_block_size=1&query=select+sleepEachRow(0.001),throwIf(number=2)from+numbers(5)+FORMAT+CSV"
...
<
0,0
0,0
__exception__
rumfyutuqkncbgau
Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(equals(__table1.number, 2_UInt8) :: 1) -> throwIf(equals(__table1.number, 2_UInt8)) UInt8 : 0'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 25.11.1.1)
262 rumfyutuqkncbgau
__exception__
파라미터가 있는 쿼리 (Queries with parameters)
파라미터가 있는 쿼리를 만들고 해당 HTTP 요청 파라미터에서 값을 전달할 수 있어요. 자세한 내용은 CLI용 파라미터 쿼리를 참고해요.
예시 (Example)
$ curl -sS "<address>?param_id=2¶m_phrase=test" -d "SELECT * FROM table WHERE int_column = {id:UInt8} and string_column = {phrase:String}"
URL 파라미터의 탭 (Tabs in URL Parameters)
쿼리 파라미터는 "escaped" 포맷에서 파싱돼요. 이는 null을 \N으로 명확하게 파싱할 수 있는 것 같은 이점이 있어요. 즉 탭 문자는 \t(또는 \와 탭)로 인코딩해야 해요. 예를 들어 다음은 abc와 123 사이에 실제 탭을 포함하며 입력 문자열이 두 값으로 분리돼요:
curl -sS "http://localhost:8123" -d "SELECT splitByChar('\t', 'abc 123')"
['abc','123']
그러나 URL 파라미터에서 %09를 사용해 실제 탭을 인코딩하려 하면 제대로 파싱되지 않아요:
curl -sS "http://localhost:8123?param_arg1=abc%09123" -d "SELECT splitByChar('\t', {arg1:String})"
Code: 457. DB::Exception: Value abc 123 cannot be parsed as String for query parameter 'arg1' because it isn't parsed completely: only 3 of 7 bytes was parsed: abc. (BAD_QUERY_PARAMETER) (version 23.4.1.869 (official build))
URL 파라미터를 사용한다면 \t를 %5C%09로 인코딩해야 해요. 예를 들어:
curl -sS "http://localhost:8123?param_arg1=abc%5C%09123" -d "SELECT splitByChar('\t', {arg1:String})"
['abc','123']
사전 정의된 HTTP 인터페이스 (Predefined HTTP Interface)
ClickHouse는 HTTP 인터페이스를 통해 특정 쿼리를 지원해요. 예를 들어 다음과 같이 테이블에 데이터를 쓸 수 있어요:
$ echo '(4),(5),(6)' | curl 'http://localhost:8123/?query=INSERT%20INTO%20t%20VALUES' --data-binary @-
ClickHouse는 Prometheus exporter 같은 서드파티 도구와 더 쉽게 통합하는 데 도움이 되는 사전 정의된 HTTP 인터페이스도 지원해요. 예를 살펴볼게요.
먼저 서버 설정 파일에 이 섹션을 추가하세요.
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>
이제 Prometheus 포맷의 데이터를 위해 URL을 직접 요청할 수 있어요:
$ 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은 다음 파라미터를 구성할 수 있어요:
methodheadersurlfull_urlhandler
각각 아래에서 설명할게요:
method는 HTTP 요청의 메서드 부분 일치를 담당해요.method는 HTTP 프로토콜의method정의를 완전히 따릅니다. 선택적 구성이에요. 설정 파일에 정의되지 않으면 HTTP 요청의 메서드 부분을 일치시키지 않아요.url은 HTTP 요청의 URL 부분(경로와 쿼리 문자열) 일치를 담당해요.url이regex:로 접두사 붙으면 RE2의 정규 표현식을 기대해요. 선택적 구성이에요. 설정 파일에 정의되지 않으면 HTTP 요청의 URL 부분을 일치시키지 않아요.full_url는url과 같지만 완전한 URL을 포함해요, 즉schema://host:port/path?query_string. 참고로 ClickHouse는 "가상 호스트"를 지원하지 않으므로host는 IP 주소예요(Host헤더의 값이 아님).empty_query_string- 요청에 쿼리 문자열(?query_string)이 없도록 보장.headers는 HTTP 요청의 헤더 부분 일치를 담당해요. RE2의 정규 표현식과 호환돼요. 선택적 구성. 설정 파일에 정의되지 않으면 HTTP 요청의 헤더 부분을 일치시키지 않아요.handler는 주요 처리 부분을 담고 있어요. 다음type을 가질 수 있어요:
다음 파라미터도:
predefined_query_handlerdynamic_query_handlerstaticredirectquery—predefined_query_handler타입과 함께 사용. 핸들러가 호출될 때 쿼리를 실행.query_param_name—dynamic_query_handler타입과 함께 사용. HTTP 요청 파라미터에서query_param_name값에 해당하는 값을 추출해 실행.status—static타입과 함께 사용. 응답 상태 코드.content_type— 어떤 타입과도 함께 사용. 응답 content-type.http_response_headers— 어떤 타입과도 함께 사용. 응답 헤더 맵. 콘텐츠 타입을 설정하는 데도 사용할 수 있음.response_content—static타입과 함께 사용. 클라이언트로 보내지는 응답 콘텐츠. 'file://' 또는 'config://' 접두사를 사용하면 파일이나 설정에서 콘텐츠를 찾아 클라이언트로 보냄.user- 쿼리를 실행할 사용자(기본 사용자는default). 참고, 이 사용자에 대한 비밀번호를 지정할 필요는 없어요.
서로 다른 type들에 대한 구성 방법은 다음에서 논의해요.
predefined_query_handler
predefined_query_handler는 Settings와 query_params 값 설정을 지원해요. predefined_query_handler 타입에서 query를 구성할 수 있어요.
query 값은 predefined_query_handler의 사전 정의된 쿼리이며, HTTP 요청이 일치할 때 ClickHouse가 실행하고 쿼리 결과를 반환해요. 필수 구성이에요.
다음 예시는 max_threads와 max_final_threads 설정의 값을 정의한 다음 시스템 테이블을 조회해 이 설정들이 성공적으로 설정됐는지 확인해요.
참고: query, play, ping 같은 기본 핸들러를 유지하려면
<defaults/>규칙을 추가하세요.
예를 들어:
<http_handlers>
<rule>
<url><![CDATA[regex:/query_param_with_url/(?P<name_1>[^/]+)]]></url>
<methods>GET</methods>
<headers>
<XXX>TEST_HEADER_VALUE</XXX>
<PARAMS_XXX><![CDATA[regex:(?P<name_2>[^/]+)]]></PARAMS_XXX>
</headers>
<handler>
<type>predefined_query_handler</type>
<query>
SELECT name, value FROM system.settings
WHERE name IN ({name_1:String}, {name_2:String})
</query>
</handler>
</rule>
<defaults/>
</http_handlers>
curl -H 'XXX:TEST_HEADER_VALUE' -H 'PARAMS_XXX:max_final_threads' 'http://localhost:8123/query_param_with_url/max_threads?max_threads=1&max_final_threads=2'
max_final_threads 2
max_threads 1
가상 파라미터 _request_body
URL 파라미터, 헤더, 쿼리 파라미터 외에도 predefined_query_handler는 특별한 가상 파라미터 _request_body를 지원해요.
이것은 원시 HTTP 요청 본문을 문자열로 담고 있어요.
이를 통해 임의의 데이터 포맷을 받아들이고 쿼리 안에서 처리할 수 있는 유연한 REST API를 만들 수 있어요.
예를 들어 _request_body를 사용해 POST 요청에서 JSON 데이터를 받아 테이블에 삽입하는 REST 엔드포인트를 구현할 수 있어요:
<http_handlers>
<rule>
<methods>POST</methods>
<url>/api/events</url>
<handler>
<type>predefined_query_handler</type>
<query>
INSERT INTO events (id, data)
SELECT {id:UInt32}, {_request_body:String}
</query>
</handler>
</rule>
<defaults/>
</http_handlers>
그런 다음 이 엔드포인트에 데이터를 보낼 수 있어요:
curl -X POST 'http://localhost:8123/api/events?id=123' \
-H 'Content-Type: application/json' \
-d '{"user": "john", "action": "login", "timestamp": "2024-01-01T10:00:00Z"}'
참고: 하나의 predefined_query_handler에서는 하나의 쿼리만 지원돼요.
dynamic_query_handler
dynamic_query_handler에서 쿼리는 HTTP 요청의 파라미터 형태로 작성돼요. 차이점은 predefined_query_handler에서는 쿼리가 설정 파일에 작성된다는 점이에요. query_param_name은 dynamic_query_handler에서 구성할 수 있어요.
ClickHouse는 HTTP 요청의 URL에서 query_param_name 값에 해당하는 값을 추출해 실행해요. query_param_name의 기본값은 /query예요. 선택적 구성이며 설정 파일에 정의가 없으면 파라미터가 전달되지 않아요.
이 기능을 실험하려면 다음 예시가 max_threads와 max_final_threads의 값을 정의하고 설정이 성공적으로 설정됐는지 조회해요.
예시:
<http_handlers>
<rule>
<headers>
<XXX>TEST_HEADER_VALUE_DYNAMIC</XXX> </headers>
<handler>
<type>dynamic_query_handler</type>
<query_param_name>query_param</query_param_name>
</handler>
</rule>
<defaults/>
</http_handlers>
curl -H 'XXX:TEST_HEADER_VALUE_DYNAMIC' 'http://localhost:8123/own?max_threads=1&max_final_threads=2¶m_name_1=max_threads¶m_name_2=max_final_threads&query_param=SELECT%20name,value%20FROM%20system.settings%20where%20name%20=%20%7Bname_1:String%7D%20OR%20name%20=%20%7Bname_2:String%7D'
max_threads 1
max_final_threads 2
static
static은 content_type, status, response_content를 반환할 수 있어요. response_content는 지정된 콘텐츠를 반환할 수 있어요.
예를 들어 "Say Hi!" 메시지를 반환하려면:
<http_handlers>
<rule>
<methods>GET</methods>
<headers><XXX>xxx</XXX></headers>
<url>/hi</url>
<handler>
<type>static</type>
<status>402</status>
<content_type>text/html; charset=UTF-8</content_type>
<http_response_headers>
<Content-Language>en</Content-Language>
<X-My-Custom-Header>43</X-My-Custom-Header>
</http_response_headers>
<response_content>Say Hi!</response_content>
</handler>
</rule>
<defaults/>
</http_handlers>
http_response_headers는 content_type 대신 콘텐츠 타입을 설정하는 데 사용할 수 있어요.
<http_handlers>
<rule>
<methods>GET</methods>
<headers><XXX>xxx</XXX></headers>
<url>/hi</url>
<handler>
<type>static</type>
<status>402</status>
<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>
<response_content>Say Hi!</response_content>
</handler>
</rule>
<defaults/>
</http_handlers>
curl -vv -H 'XXX:xxx' 'http://localhost:8123/hi'
* Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /hi HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 402 Payment Required
< Date: Wed, 29 Apr 2020 03:51:26 GMT
< Connection: Keep-Alive
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
* Connection #0 to host localhost left intact
Say Hi!%
설정에서 콘텐츠를 찾아 클라이언트로 보내기.
<get_config_static_handler><![CDATA[<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>]]></get_config_static_handler>
<http_handlers>
<rule>
<methods>GET</methods>
<headers><XXX>xxx</XXX></headers>
<url>/get_config_static_handler</url>
<handler>
<type>static</type>
<response_content>config://get_config_static_handler</response_content>
</handler>
</rule>
</http_handlers>
$ curl -v -H 'XXX:xxx' 'http://localhost:8123/get_config_static_handler'
* Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /get_config_static_handler HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 200 OK
< Date: Wed, 29 Apr 2020 04:01:24 GMT
< Connection: Keep-Alive
< Content-Type: text/plain; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
* Connection #0 to host localhost left intact
<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>%
파일에서 콘텐츠를 찾아 클라이언트로 보내기:
<http_handlers>
<rule>
<methods>GET</methods>
<headers><XXX>xxx</XXX></headers>
<url>/get_absolute_path_static_handler</url>
<handler>
<type>static</type>
<content_type>text/html; charset=UTF-8</content_type>
<http_response_headers>
<ETag>737060cd8c284d8af7ad3082f209582d</ETag>
</http_response_headers>
<response_content>file:///absolute_path_file.html</response_content>
</handler>
</rule>
<rule>
<methods>GET</methods>
<headers><XXX>xxx</XXX></headers>
<url>/get_relative_path_static_handler</url>
<handler>
<type>static</type>
<content_type>text/html; charset=UTF-8</content_type>
<http_response_headers>
<ETag>737060cd8c284d8af7ad3082f209582d</ETag>
</http_response_headers>
<response_content>file://./relative_path_file.html</response_content>
</handler>
</rule>
</http_handlers>
$ user_files_path='/var/lib/clickhouse/user_files'
$ sudo echo "<html><body>Relative Path File</body></html>" > $user_files_path/relative_path_file.html
$ sudo echo "<html><body>Absolute Path File</body></html>" > $user_files_path/absolute_path_file.html
$ curl -vv -H 'XXX:xxx' 'http://localhost:8123/get_absolute_path_static_handler'
* Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /get_absolute_path_static_handler HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 200 OK
< Date: Wed, 29 Apr 2020 04:18:16 GMT
< Connection: Keep-Alive
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
<html><body>Absolute Path File</body></html>
* Connection #0 to host localhost left intact
$ curl -vv -H 'XXX:xxx' 'http://localhost:8123/get_relative_path_static_handler'
* Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /get_relative_path_static_handler HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 200 OK
< Date: Wed, 29 Apr 2020 04:18:31 GMT
< Connection: Keep-Alive
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
<html><body>Relative Path File</body></html>
* Connection #0 to host localhost left intact
redirect
redirect는 location으로 302 리다이렉트를 해요.
예를 들어 ClickHouse play에 대해 set user를 자동으로 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 응답 헤더 (HTTP response headers)
ClickHouse는 구성할 수 있는 어떤 종류의 핸들러에든 적용할 수 있는 사용자 정의 HTTP 응답 헤더를 구성할 수 있게 해 줘요. 이 헤더들은 http_response_headers 설정으로 설정할 수 있으며, 헤더 이름과 값을 나타내는 키-값 쌍을 받아들여요. 이 기능은 ClickHouse HTTP 인터페이스 전반에 걸쳐 사용자 정의 보안 헤더, CORS 정책 또는 다른 HTTP 헤더 요구 사항을 구현하는 데 특히 유용해요.
예를 들어 다음에 대한 헤더를 구성할 수 있어요:
- 일반 쿼리 엔드포인트
- 웹 UI
- 헬스 체크.
common_http_response_headers를 지정할 수도 있어요. 이것들은 구성에 정의된 모든 http 핸들러에 적용돼요.
헤더는 구성된 모든 핸들러의 HTTP 응답에 포함돼요.
아래 예시에서 모든 서버 응답은 X-My-Common-Header와 X-My-Custom-Header 두 개의 사용자 정의 헤더를 포함해요.
<clickhouse>
<http_handlers>
<common_http_response_headers>
<X-My-Common-Header>Common header</X-My-Common-Header>
</common_http_response_headers>
<rule>
<methods>GET</methods>
<url>/ping</url>
<handler>
<type>ping</type>
<http_response_headers>
<X-My-Custom-Header>Custom indeed</X-My-Custom-Header>
</http_response_headers>
</handler>
</rule>
</http_handlers>
</clickhouse>
HTTP 스트리밍 중 예외 시 유효한 JSON/XML 응답 (Valid JSON/XML response on exception during HTTP streaming)
HTTP를 통한 쿼리 실행 중 데이터의 일부가 이미 전송된 후 예외가 발생할 수 있어요. 보통 예외가 평문 텍스트로 클라이언트에 전송돼요.
데이터 출력에 특정 데이터 포맷이 사용되었고 그 출력이 지정된 데이터 포맷에 관해 유효하지 않게 될 수 있더라도 말이죠.
이를 방지하려면 http_write_exception_in_output_format 설정(기본적으로 비활성화)을 사용할 수 있는데, 이는 ClickHouse가 지정된 포맷으로 예외를 쓰도록 지시해요(현재 XML과 JSON* 포맷 지원).
예시:
$ curl 'http://localhost:8123/?query=SELECT+number,+throwIf(number>3)+from+system.numbers+format+JSON+settings+max_block_size=1&http_write_exception_in_output_format=1'
{
"meta":
[
{
"name": "number",
"type": "UInt64"
},
{
"name": "throwIf(greater(number, 2))",
"type": "UInt8"
}
],
"data":
[
{
"number": "0",
"throwIf(greater(number, 2))": 0
},
{
"number": "1",
"throwIf(greater(number, 2))": 0
},
{
"number": "2",
"throwIf(greater(number, 2))": 0
}
],
"rows": 3,
"exception": "Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(greater(number, 2) :: 2) -> throwIf(greater(number, 2)) UInt8 : 1'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 23.8.1.1)"
}
$ curl 'http://localhost:8123/?query=SELECT+number,+throwIf(number>2)+from+system.numbers+format+XML+settings+max_block_size=1&http_write_exception_in_output_format=1'
<?xml version='1.0' encoding='UTF-8' ?>
<result>
<meta>
<columns>
<column>
<name>number</name>
<type>UInt64</type>
</column>
<column>
<name>throwIf(greater(number, 2))</name>
<type>UInt8</type>
</column>
</columns>
</meta>
<data>
<row>
<number>0</number>
<field>0</field>
</row>
<row>
<number>1</number>
<field>0</field>
</row>
<row>
<number>2</number>
<field>0</field>
</row>
</data>
<rows>3</rows>
<exception>Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(greater(number, 2) :: 2) -> throwIf(greater(number, 2)) UInt8 : 1'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 23.8.1.1)</exception>
</result>