Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

واجهة HTTP

المتطلبات الأساسية

ستحتاج إلى ما يلي للأمثلة الواردة في هذه المقالة:

  • أن يكون لديك مثيل عامل من ClickHouse server
  • أن يكون curl مثبّتًا لديك. على Ubuntu أو Debian، شغّل sudo apt install curl أو راجع هذه الوثائق للحصول على إرشادات التثبيت.

نظرة عامة

تتيح لك واجهة HTTP استخدام ClickHouse على أي منصة ومن أي لغة برمجة عبر واجهة برمجة تطبيقات REST. وتُعد واجهة HTTP أكثر محدودية من الواجهة الأصلية، لكنها توفر دعماً أفضل للغات البرمجة.

بشكل افتراضي، يستمع clickhouse-server على المنافذ التالية:

  • المنفذ 8123 لـ HTTP
  • يمكن تمكين المنفذ 8443 لـ HTTPS

إذا أجريت طلب GET / من دون أي معلمات، فسيُعاد رمز الاستجابة 200 مع السلسلة "Ok.":

$ curl 'http://localhost:8123/'
Ok.

"Ok." هي القيمة الافتراضية المعرَّفة في http_server_default_response، ويمكن تغييرها عند الحاجة.

راجع أيضًا: محاذير رموز استجابة HTTP.

واجهة مستخدم الويب

يتضمن ClickHouse واجهة مستخدم عبر الويب، ويمكن الوصول إليها من العنوان التالي:

http://localhost:8123/play

تدعم واجهة الويب عرض التقدّم أثناء تنفيذ الاستعلام، وإلغاء الاستعلام، وبث النتائج. كما تتضمن ميزة غير معلنة لعرض المخططات والرسوم البيانية لخطوط تنفيذ الاستعلام.

بعد تنفيذ استعلام بنجاح، يظهر زر تنزيل يتيح لك تنزيل نتائج الاستعلام بتنسيقات مختلفة، بما في ذلك CSV وTSV وJSON وJSONLines وParquet وMarkdown أو أي تنسيق مخصص يدعمه ClickHouse. تستخدم ميزة التنزيل ذاكرة تخزين مؤقت للاستعلامات لاسترداد النتائج بكفاءة من دون إعادة تنفيذ الاستعلام. وستنزّل مجموعة النتائج الكاملة حتى إذا كانت واجهة الويب قد عرضت صفحة واحدة فقط من بين صفحات عديدة.

صُممت واجهة الويب للمحترفين مثلك.

لقطة شاشة لواجهة ويب ClickHouse

في النصوص البرمجية الخاصة بفحوصات الحالة، استخدم الطلب GET /ping. يعيد هذا المعالج دائمًا "Ok." (مع فاصل سطر في النهاية). وهو متاح بدءًا من الإصدار 18.12.13. انظر أيضًا إلى /replicas_status للتحقق من تأخر النسخة المتماثلة.

$ curl 'http://localhost:8123/ping'
Ok.
$ curl 'http://localhost:8123/replicas_status'
Ok.

الاستعلام عبر HTTP/HTTPS

للاستعلام عبر HTTP/HTTPS، توجد ثلاثة خيارات:

  • إرسال الطلب كمعلمة URL باسم 'query'
  • استخدام طريقة POST.
  • إرسال بداية الاستعلام في المعلمة 'query'، ثم إرسال الباقي باستخدام POST

إذا نجح الطلب، فستتلقى رمز الاستجابة 200 والنتيجة في جسم الاستجابة. وإذا حدث خطأ، فستتلقى رمز الاستجابة 500 ونصًا يصف الخطأ في جسم الاستجابة.

تكون الطلبات التي تستخدم GET من النوع 'readonly'. وهذا يعني أنه بالنسبة إلى الاستعلامات التي تعدّل البيانات، لا يمكنك استخدام سوى طريقة POST. ويمكنك إرسال الاستعلام نفسه إما في body الخاص بـ POST أو في معلمة URL. لنلقِ نظرة على بعض الأمثلة.

في المثال أدناه، يُستخدم curl لإرسال الاستعلام SELECT 1. لاحظ استخدام ترميز URL للمسافة: %20.

commandbash
curl 'http://localhost:8123/?query=SELECT%201'
Responseresponse
1

في هذا المثال، يُستخدَم wget مع الخيارين -nv (بدون مخرجات تفصيلية) و-O- لطباعة النتيجة في الطرفية. في هذه الحالة، لا حاجة إلى استخدام ترميز URL للمسافة:

commandbash
wget -nv -O- 'http://localhost:8123/?query=SELECT 1'
1

في هذا المثال، نمرّر طلب HTTP خامًا إلى netcat:

commandbash
echo -ne 'GET /?query=SELECT%201 HTTP/1.0\r\n\r\n' | nc localhost 8123
responseresponse
HTTP/1.0 200 OK
X-ClickHouse-Summary: {"read_rows":"1","read_bytes":"1","written_rows":"0","written_bytes":"0","total_rows_to_read":"1","result_rows":"0","result_bytes":"0","elapsed_ns":"4505959","memory_usage":"1111711"}
Date: Tue, 11 Nov 2025 18:16:01 GMT
Connection: Close
Content-Type: text/tab-separated-values; charset=UTF-8
Access-Control-Expose-Headers: X-ClickHouse-Query-Id,X-ClickHouse-Summary,X-ClickHouse-Server-Display-Name,X-ClickHouse-Format,X-ClickHouse-Timezone,X-ClickHouse-Exception-Code,X-ClickHouse-Exception-Tag
X-ClickHouse-Server-Display-Name: MacBook-Pro.local
X-ClickHouse-Query-Id: ec0d8ec6-efc4-4e1d-a14f-b748e01f5294
X-ClickHouse-Format: TabSeparated
X-ClickHouse-Timezone: Europe/London
X-ClickHouse-Exception-Tag: dngjzjnxkvlwkeua

1

كما ترى، فإن الأمر curl غير عملي إلى حدّ ما، إذ يجب ترميز المسافات بصيغة URL. ورغم أن wget يتولى ترميز كل شيء بنفسه، فإننا لا نوصي باستخدامه لأنه لا يعمل جيدًا عبر HTTP 1.1 عند استخدام keep-alive و Transfer-Encoding: chunked.

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

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

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

إذا أُرسل جزء من الاستعلام في المعلَمة، وأُرسل جزء آخر في طلب POST، فسيُدرَج فاصل سطر بين جزأَي البيانات هذين. على سبيل المثال، لن يعمل هذا:

$ echo 'ECT 1' | curl 'http://localhost:8123/?query=SEL' --data-binary @-
Code: 59, e.displayText() = DB::Exception: Syntax error: failed at position 0: SEL
ECT 1
, expected One of: SHOW TABLES, SHOW DATABASES, SELECT, INSERT, CREATE, ATTACH, RENAME, DROP, DETACH, USE, SET, OPTIMIZE., e.what() = DB::Exception

افتراضيًا، تُعاد البيانات بتنسيق TabSeparated.

تُستخدم عبارة FORMAT في الاستعلام لطلب أي تنسيق آخر. على سبيل المثال:

commandbash
wget -nv -O- 'http://localhost:8123/?query=SELECT 1, 2, 3 FORMAT JSON'
Responseresponse
{
    "meta":
    [
        {
            "name": "1",
            "type": "UInt8"
        },
        {
            "name": "2",
            "type": "UInt8"
        },
        {
            "name": "3",
            "type": "UInt8"
        }
    ],

    "data":
    [
        {
            "1": 1,
            "2": 2,
            "3": 3
        }
    ],

    "rows": 1,

    "statistics":
    {
        "elapsed": 0.000515,
        "rows_read": 1,
        "bytes_read": 1
    }
}

يمكنك استخدام معلمة URL ‏default_format لتحديد تنسيق افتراضي بدلاً من TabSeparated. تحدد ترويسة 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 وإنشاء الاستعلامات

متاح في ClickHouse 26.8 والإصدارات الأحدث.

يمكن لواجهة HTTP تفسير مسار URL باعتباره قاعدة بيانات أو جدولًا أو تنسيق إخراج أو طريقة ضغط. ويمكن لمعلمات URL بعد ذلك تحديد شكل النتيجة، بحيث لا تتطلب طلبات القراءة البسيطة استخدام SQL. تكون هذه الميزات معطّلة افتراضيًا ويجب تمكينها صراحةً.

تفعيل التوجيه عبر المسارات

يُفعَّل تفسير المسارات على مستويين:

  1. فعِّل إعداد التكوين http_allow_path_requests على مستوى الخادم، الذي يتيح لواجهة HTTP توجيه الطلبات ذات نمط المسار إلى معالج الاستعلامات:
<clickhouse>
    <http_allow_path_requests>1</http_allow_path_requests>
</clickhouse>
  1. فعّل الإعدادات المطلوبة لكل مستخدم:
الإعداد التأثير
http_allow_table_as_file يفسّر آخر مكوّن في المسار على أنه table أو table.format أو table.format.compression.
http_allow_database_as_path يفسّر مكوّن المسار البادئ /database/ على أنه قاعدة البيانات الحالية.
http_allow_filters_as_path يفسّر مكوّنات المسار /name=value/ بنمط Hive على أنها عوامل تصفية WHERE.
http_allow_filters_as_unrecognized_url_parameters يفسّر معلمات URL غير المعروفة على أنها عوامل تصفية WHERE.

الوصول إلى الجداول كملفات

عند تمكين http_allow_table_as_file، يُعالَج الطلب الموجّه إلى /table.format.compression على أنه SELECT * FROM table. فعّل http_allow_database_as_path لاستخدام /database/table.format.compression.

# 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 متكافئان.

تتجاوز معلمة URL الصريحة format أو output_format التنسيق المحدد في المسار. أما default_format فلا يتجاوزه، إذ يوفّر التنسيق المستخدم فقط عندما لا يحدد أي شيء آخر تنسيقًا، ويكون امتداد المسار أكثر تحديدًا. يجب أن تتطابق معلمة compression الصريحة مع الضغط المحدد في المسار؛ وتؤدي القيم المتعارضة إلى استثناء.

إنشاء استعلام

تُغلّف الإعدادات التالية الاستعلام الأساسي في صورة جدول مشتق. ويمكن استخدامها معًا أو مع استعلام موجود. يمكنك تمريرها كمعلمات URL عبر HTTP، أو ضمن عبارة SETTINGS في الاستعلام، أو عبر ملف تعريف المستخدم.

الإعداد التأثير
select SELECT <expression_list> FROM (…)
filter يضيف WHERE <expression>. وتُدمج معلمات URL المتعددة لـ filter باستخدام 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'

تعديل استعلام موجود

لا تقتصر إعدادات الإنشاء على طلبات المسار، بل تؤثر أيضًا في الاستعلام الذي تكتبه بنفسك. يصبح الاستعلام جدولًا مشتقًا، لذا تُطبَّق الإعدادات على نتيجته بدلًا من دمجها فيه. على سبيل المثال، يُنفَّذ ?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 المصدرية. وللتأثير في المصدر، ضع الإعداد في عبارة SETTINGS الخاصة بـSELECT نفسها:

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

تجاوز التنسيقات والضغط

الإعداد التأثير
output_format يتجاوز تنسيق الإخراج. وتكون له أولوية على عبارة FORMAT في الاستعلام وامتداد المسار وformat وdefault_format. ويمكن أيضًا ضبطه باستخدام الترويسة X-ClickHouse-Format.
input_format يتجاوز تنسيق الإدخال لعملية INSERT. وتكون له أولوية على عبارة FORMAT في الاستعلام وformat.
format يتجاوز التنسيق في كلا الاتجاهين، ما لم يُوفَّر إعداد خاص باتجاه محدد.
default_format يحدد تنسيق الإخراج عندما لا يتضمن الاستعلام عبارة FORMAT أو امتداد مسار أو أي تجاوز آخر للتنسيق.
compression يضغط جسم الاستجابة، مثلًا باستخدام compression=gz. وهو مستقل عن Content-Encoding في HTTP وعن المعلَمة الأصلية compress في ClickHouse.

تعمل إعدادات التنسيق أيضًا مع بروتوكولات أخرى، بما فيها العميل الأصلي وclickhouse-local. ويتوافق input_format وoutput_format مع الخيارين --input-format و--output-format. ويرتبط الخيار --format بإعداد format ثنائي الاتجاه في clickhouse-local، بينما يحتفظ في clickhouse-client بمعناه التاريخي المقتصر على الإخراج ويرتبط بـ output_format.

يُستخدم compression خصيصًا لتشكيل استجابة HTTP، وتتم معالجته قبل تنفيذ الاستعلام. حدده عبر معلمة URL في HTTP، أو امتداد مسار، أو ملف تعريف مستخدم. ويُرفض ضمن عبارة SETTINGS داخل الاستعلام.

تتضمن استجابات HTTP الثنائية والمضغوطة ترويسة Content-Disposition: attachment; filename=…. ويُشتق اسم الملف من مسار URL، أو يُستخدم result.<format>.<compression> إذا لم يوفر المسار اسمًا.

استخدام جدول مسار مع استعلام

عندما يشير المسار إلى جدول وتوفّر أيضًا المعلَمة query، يُتاح جدول المسار عبر implicit_table_at_top_level. تقرأ عبارة SELECT التي لا تحتوي على عبارة FROM من جدول المسار:

# 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، فلا يحدد مكوّن المسار سوى اسم ملف التنزيل.

استعلامات INSERT عبر HTTP/HTTPS

تُعد طريقة POST لنقل البيانات ضرورية لاستعلامات INSERT. في هذه الحالة، يمكنك كتابة بداية الاستعلام في معلمة URL، واستخدام POST لتمرير البيانات المراد إدراجها. ويمكن أن تكون هذه البيانات، على سبيل المثال، ملف تفريغ من MySQL مفصولًا بعلامات جدولة. وبهذه الطريقة، يحل استعلام INSERT محل LOAD DATA LOCAL INFILE في MySQL.

أمثلة

لإنشاء جدول:

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

لاستخدام استعلام INSERT المعروف لإدراج البيانات:

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

لإرسال البيانات منفصلة عن الاستعلام:

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

يمكن تحديد أي صيغة بيانات. على سبيل المثال، يمكن تحديد صيغة 'Values'، وهي الصيغة نفسها المستخدمة عند كتابة INSERT INTO t VALUES:

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

لإدراج البيانات من ملف تفريغ مفصول بعلامات جدولة، حدِّد التنسيق المقابل:

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

لقراءة محتويات الجدول:

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

لحذف الجدول:

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

في الطلبات الناجحة التي لا تُرجع جدول بيانات، يُعاد جسم الاستجابة فارغًا.

الضغط

يمكن استخدام الضغط لتقليل حركة مرور الشبكة عند نقل كميات كبيرة من البيانات، أو لإنشاء ملفات تفريغ مضغوطة مباشرةً.

يمكنك استخدام تنسيق الضغط الداخلي في ClickHouse عند نقل البيانات. تكون البيانات المضغوطة بتنسيق غير قياسي، وستحتاج إلى برنامج clickhouse-compressor للتعامل معها. ويُثبَّت هذا البرنامج افتراضيًا مع حزمة clickhouse-client.

لزيادة كفاءة إدراج البيانات، عطّل التحقق من checksum من جهة الخادم عند فك الضغط باستخدام الإعداد http_native_compression_disable_checksumming_on_decompress.

إذا حدّدت compress=1 في URL، فسيقوم الخادم بضغط البيانات التي يرسلها إليك. وإذا حدّدت decompress=1 في URL، فسيقوم الخادم بفك ضغط البيانات التي تمرّرها في طريقة POST.

يمكنك أيضًا اختيار استخدام ضغط HTTP. يدعم ClickHouse طرق الضغط التالية:

  • gzip
  • br
  • deflate
  • xz
  • zstd
  • lz4
  • bz2
  • snappy

لإرسال طلب POST مضغوط، ألحِق ترويسة الطلب Content-Encoding: compression_method.

ولكي يقوم ClickHouse بضغط الاستجابة، ألحِق الترويسة Accept-Encoding: compression_method بالطلب.

يمكنك ضبط مستوى ضغط البيانات باستخدام الإعداد http_zlib_compression_level لجميع طرق الضغط.

أمثلة

لإرسال البيانات المضغوطة إلى الخادم:

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

قاعدة البيانات الافتراضية

يمكنك استخدام المعلمة 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. أو يمكنك دائمًا تحديد قاعدة البيانات بوضع نقطة قبل اسم الجدول.

المصادقة

يمكن إدخال اسم المستخدم وكلمة المرور بإحدى الطرق الثلاث التالية:

  1. باستخدام المصادقة الأساسية عبر HTTP.

على سبيل المثال:

echo 'SELECT 1' | curl 'http://user:password@localhost:8123/' -d @-
  1. في معلمتَي URL user وpassword

على سبيل المثال:

echo 'SELECT 1' | curl 'http://localhost:8123/?user=user&password=password' -d @-
  1. استخدام ترويستَي 'X-ClickHouse-User' و'X-ClickHouse-Key'

على سبيل المثال:

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

إذا لم يُحدَّد اسم المستخدم، فسيُستخدم الاسم default. وإذا لم تُحدَّد كلمة المرور، فستُستخدم كلمة مرور فارغة. يمكنك أيضًا استخدام معلمات URL لتحديد أي إعدادات لمعالجة استعلام واحد أو ملفات تعريف كاملة للإعدادات.

على سبيل المثال:

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

لمزيد من المعلومات، راجع:

استخدام جلسات ClickHouse في بروتوكول HTTP

يمكنك أيضًا استخدام جلسات ClickHouse ضمن بروتوكول HTTP. للقيام بذلك، عليك إضافة معلمة GETsession_id إلى الطلب. ويمكنك استخدام أي سلسلة نصية كمعرّف للجلسة.

افتراضيًا، تُنهى الجلسة بعد 60 ثانية من عدم النشاط. لتغيير هذه المهلة (بالثواني)، عدّل الإعداد default_session_timeout في تهيئة الخادم، أو أضف معلمة GETsession_timeout إلى الطلب.

للتحقق من حالة الجلسة، استخدم المعلمة session_check=1. ولا يمكن تنفيذ أكثر من استعلام واحد في الوقت نفسه ضمن الجلسة الواحدة.

يمكنك تلقّي معلومات حول تقدّم الاستعلام في ترويسات الاستجابة X-ClickHouse-Progress. للقيام بذلك، فعّل send_progress_in_http_headers.

فيما يلي مثال على تسلسل الترويسات:

X-ClickHouse-Progress: {"read_rows":"261636","read_bytes":"2093088","total_rows_to_read":"1000000","elapsed_ns":"14050417","memory_usage":"22205975"}
X-ClickHouse-Progress: {"read_rows":"654090","read_bytes":"5232720","total_rows_to_read":"1000000","elapsed_ns":"27948667","memory_usage":"83400279"}
X-ClickHouse-Progress: {"read_rows":"1000000","read_bytes":"8000000","total_rows_to_read":"1000000","elapsed_ns":"38002417","memory_usage":"80715679"}

حقول الترويسة المحتملة هي:

Header field Description
read_rows عدد الصفوف المقروءة.
read_bytes حجم البيانات المقروءة بالبايت.
total_rows_to_read العدد الإجمالي للصفوف المطلوب قراءتها.
written_rows عدد الصفوف المكتوبة.
written_bytes حجم البيانات المكتوبة بالبايت.
elapsed_ns وقت تشغيل الاستعلام بالنانوثانية.
memory_usage مقدار الذاكرة بالبايت التي يستخدمها الاستعلام. (متاح بدءًا من v25.11)

لا تتوقف الطلبات الجارية تلقائيًا إذا فُقد اتصال HTTP. يُجرى التحليل وتنسيق البيانات على جانب الخادم، وقد لا يكون استخدام الشبكة فعّالًا.

تتوفر المعلمات الاختيارية التالية:

Parameters Description
query_id (optional) يمكن تمريره بصفته معرّف الاستعلام (أي سلسلة نصية). replace_running_query
quota_key (optional) يمكن تمريره بصفته مفتاح الحصة (أي سلسلة نصية). "Quotas"

تتيح واجهة HTTP تمرير بيانات خارجية (جداول مؤقتة خارجية) لاستخدامها في الاستعلام. لمزيد من المعلومات، راجع "البيانات الخارجية لمعالجة الاستعلامات".

تخزين الاستجابة مؤقتًا

يمكن تمكين تخزين الاستجابة مؤقتًا على جانب الخادم. تُوفَّر معلمات URL التالية لهذا الغرض:

  • buffer_size
  • wait_end_of_query

يمكن استخدام الإعدادات التالية:

يحدِّد buffer_size عدد البايتات من النتيجة التي ستُخزَّن مؤقتًا في ذاكرة الخادم. وإذا كان محتوى النتيجة أكبر من هذه العتبة، فستُكتب البيانات المخزنة مؤقتًا إلى قناة HTTP، وتُرسَل البيانات المتبقية مباشرةً إلى قناة HTTP.

ولضمان تخزين الاستجابة كاملةً مؤقتًا، اضبط wait_end_of_query=1. في هذه الحالة، ستُخزَّن البيانات التي لا تُحفَظ في الذاكرة مؤقتًا في ملف مؤقت على الخادم.

على سبيل المثال:

curl -sS 'http://localhost:8123/?max_result_bytes=4000000&buffer_size=3000000&wait_end_of_query=1' -d 'SELECT toUInt8(number) FROM system.numbers LIMIT 9000000 FORMAT RowBinary'

تعيين دور باستخدام معلمات الاستعلام

أُضيفت هذه الميزة في ClickHouse 24.4.

في حالات معيّنة، قد يلزم تعيين الدور الممنوح أولًا قبل تنفيذ التعليمة نفسها. ومع ذلك، لا يمكن إرسال SET ROLE والتعليمة معًا، لأن العبارات المتعددة غير مسموح بها:

curl -sS "http://localhost:8123" --data-binary "SET ROLE my_role;SELECT * FROM my_table;"

ينتج عن الأمر أعلاه خطأ:

Code: 62. DB::Exception: Syntax error (Multi-statements are not allowed)

لتجاوز هذا القيد، استخدم معلَمة الاستعلام role بدلاً من ذلك:

curl -sS "http://localhost:8123?role=my_role" --data-binary "SELECT * FROM my_table;"

هذا يعادل تنفيذ SET ROLE my_role قبل التعليمة.

بالإضافة إلى ذلك، يمكن تحديد عدة معلمات استعلام باسم role:

curl -sS "http://localhost:8123?role=my_role&role=my_other_role" --data-binary "SELECT * FROM my_table;"

في هذه الحالة، يعمل ?role=my_role&role=my_other_role بشكل مماثل لتنفيذ SET ROLE my_role, my_other_role قبل العبارة.

محاذير رموز استجابة HTTP

نظرًا لقيود بروتوكول HTTP، فإن رمز الاستجابة HTTP 200 لا يضمن نجاح الاستعلام.

إليك مثالًا:

curl -v -Ss "http://localhost:8123/?max_block_size=1&query=select+sleepEachRow(0.001),throwIf(number=2)from+numbers(5)"
*   Trying 127.0.0.1:8123...
...
< HTTP/1.1 200 OK
...
Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(equals(number, 2) :: 1) -> throwIf(equals(number, 2))

يرجع سبب هذا السلوك إلى طبيعة بروتوكول HTTP. إذ تُرسَل ترويسة HTTP أولًا مع رمز HTTP بقيمة 200، ثم يُرسَل جسم HTTP، وبعد ذلك يُحقَن الخطأ في الجسم كنص عادي.

هذا السلوك مستقل عن التنسيق المستخدم، سواء كان Native أو TSV أو JSON؛ إذ ستظهر رسالة الخطأ دائمًا في وسط دفق الاستجابة.

يمكنك التخفيف من هذه المشكلة عبر تمكين wait_end_of_query=1 (تخزين الاستجابة مؤقتًا). في هذه الحالة، يتأخر إرسال ترويسة HTTP إلى أن يُحسَم الاستعلام بالكامل. ومع ذلك، لا يحل هذا المشكلة بالكامل، لأن النتيجة يجب أن تظل ضمن http_response_buffer_size، كما أن إعدادات أخرى مثل send_progress_in_http_headers قد تتداخل مع تأخير الترويسة.

تكون مثل هذه الاستثناءات في ClickHouse ذات تنسيق متسق للاستثناءات كما هو موضح أدناه، بغض النظر عن التنسيق المستخدم (مثل Native وTSV وJSON وغيرها) عندما تكون http_write_exception_in_output_format=0 (الافتراضي). وهذا يسهّل تحليل رسائل الخطأ واستخراجها من جهة العميل.

\r\n
__exception__\r\n
<TAG>\r\n
<error message>\r\n
<message_length> <TAG>\r\n
__exception__\r\n

حيث يكون <TAG> وسمًا عشوائيًا بطول 16 بايت، وهو نفس الوسم المُرسَل في ترويسة الاستجابة X-ClickHouse-Exception-Tag. أما <error message> فهي رسالة الاستثناء الفعلية (يمكن العثور على طولها الدقيق في <message_length>). ويمكن أن يصل حجم كتلة الاستثناء الكاملة الموضحة أعلاه إلى 16 KiB.

فيما يلي مثال بتنسيق JSON

$ curl -v -Ss "http://localhost:8123/?max_block_size=1&query=select+sleepEachRow(0.001),throwIf(number=2)from+numbers(5)+FORMAT+JSON"
...
{
    "meta":
    [
        {
            "name": "sleepEachRow(0.001)",
            "type": "UInt8"
        },
        {
            "name": "throwIf(equals(number, 2))",
            "type": "UInt8"
        }
    ],

    "data":
    [
        {
            "sleepEachRow(0.001)": 0,
            "throwIf(equals(number, 2))": 0
        },
        {
            "sleepEachRow(0.001)": 0,
            "throwIf(equals(number, 2))": 0
        }
__exception__
dmrdfnujjqvszhav
Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(equals(__table1.number, 2_UInt8) :: 1) -> throwIf(equals(__table1.number, 2_UInt8)) UInt8 : 0'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 25.11.1.1)
262 dmrdfnujjqvszhav
__exception__

فيما يلي مثال مشابه ولكن بصيغة CSV

$ curl -v -Ss "http://localhost:8123/?max_block_size=1&query=select+sleepEachRow(0.001),throwIf(number=2)from+numbers(5)+FORMAT+CSV"
...
<
0,0
0,0

__exception__
rumfyutuqkncbgau
Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(equals(__table1.number, 2_UInt8) :: 1) -> throwIf(equals(__table1.number, 2_UInt8)) UInt8 : 0'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 25.11.1.1)
262 rumfyutuqkncbgau
__exception__

استعلامات بمعلمات

يمكنك إنشاء استعلام بمعلمات وتمرير قيمها عبر معلمات طلب HTTP المقابلة. لمزيد من المعلومات، راجع الاستعلامات بمعلمات في CLI.

مثال

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

علامات الجدولة في معلمات URL

تُحلَّل معلمات الاستعلام من صيغة "escaped". ولهذا بعض المزايا، مثل إمكانية تحليل قيم NULL دون لبس على أنها \N. وهذا يعني أن محرف الجدولة يجب ترميزه على هيئة \t (أو \ ثم علامة جدولة). على سبيل المثال، يحتوي ما يلي على علامة جدولة فعلية بين abc و123، وتُقسَّم سلسلة الإدخال إلى قيمتين:

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

ومع ذلك، إذا حاولت ترميز محرف جدولة فعلي باستخدام %09 في مَعلمة URL، فلن يُحلَّل بشكل صحيح:

curl -sS "http://localhost:8123?param_arg1=abc%09123" -d "SELECT splitByChar('\t', {arg1:String})"
Code: 457. DB::Exception: Value abc    123 cannot be parsed as String for query parameter 'arg1' because it isn't parsed completely: only 3 of 7 bytes was parsed: abc. (BAD_QUERY_PARAMETER) (version 23.4.1.869 (official build))

إذا كنت تستخدم معلمات URL، فستحتاج إلى ترميز \t على هيئة %5C%09. على سبيل المثال:

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

واجهة HTTP المُعرَّفة مسبقًا

يدعم ClickHouse استعلامات محددة عبر واجهة HTTP. على سبيل المثال، يمكنك إدخال البيانات في جدول كما يلي:

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

يدعم ClickHouse أيضًا واجهة HTTP المحددة مسبقًا، والتي يمكن أن تساعدك على التكامل بسهولة أكبر مع أدوات خارجية مثل Prometheus exporter. لنلقِ نظرة على مثال.

أولًا، أضِف هذا القسم إلى ملف تهيئة الخادم.

تمت تهيئة http_handlers ليتضمن عدة rule. وسيطابق ClickHouse طلبات HTTP الواردة مع النوع المحدد مسبقًا في rule، وستُشغِّل أول قاعدة تتم مطابقتها المعالج. بعد ذلك، سينفّذ ClickHouse الاستعلام المحدد مسبقًا المقابل إذا نجحت المطابقة.

config.xmlyaml
<http_handlers>
    <rule>
        <url>/predefined_query</url>
        <methods>POST,GET</methods>
        <handler>
            <type>predefined_query_handler</type>
            <query>SELECT * FROM system.metrics LIMIT 5 FORMAT Template SETTINGS format_template_resultset = 'prometheus_template_output_format_resultset', format_template_row = 'prometheus_template_output_format_row', format_template_rows_between_delimiter = '\n'</query>
        </handler>
    </rule>
    <rule>...</rule>
    <rule>...</rule>
</http_handlers>

يمكنك الآن طلب URL مباشرةً للحصول على البيانات بتنسيق Prometheus:

$ curl -v 'http://localhost:8123/predefined_query'
*   Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /predefined_query HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Tue, 28 Apr 2020 08:52:56 GMT
< Connection: Keep-Alive
< Content-Type: text/plain; charset=UTF-8
< X-ClickHouse-Server-Display-Name: i-mloy5trc
< Transfer-Encoding: chunked
< X-ClickHouse-Query-Id: 96fe0052-01e6-43ce-b12a-6b7370de6e8a
< X-ClickHouse-Format: Template
< X-ClickHouse-Timezone: Asia/Shanghai
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
# HELP "Query" "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 مسؤولًا عن مطابقة جزء method في طلب HTTP. ويتوافق method بالكامل مع تعريف [method] (https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) في HTTP protocol. وهو إعداد اختياري. إذا لم يكن معرّفًا في configuration file، فلن يطابق جزء method من طلب HTTP.

  • يكون url مسؤولًا عن مطابقة جزء URL (المسار وquery string) من طلب HTTP. إذا كانت url مسبوقة بـ regex:، فإنه يتوقع regular expression بصيغة RE2. وهو إعداد اختياري. إذا لم يكن معرّفًا في configuration file، فلن يطابق جزء URL من طلب HTTP.

  • full_url مثل url، لكنه يتضمن URL كاملًا، أي schema://host:port/path?query_string. ملاحظة: لا يدعم ClickHouse "virtual hosts"، لذا يكون host عنوان IP (وليس قيمة header ‏Host).

  • empty_query_string — يضمن عدم وجود query string (?query_string) في الطلب

  • تكون headers مسؤولة عن مطابقة جزء header من طلب HTTP. وهي متوافقة مع regular expression الخاصة بـ RE2. وهي إعداد اختياري . إذا لم تكن معرّفة في configuration file، فلن تطابق جزء header من طلب HTTP.

  • يحتوي handler على جزء processing الرئيسي.

    ويمكن أن يكون له type التالي:

    والمعلمات التالية:

    • query — يُستخدم مع النوع predefined_query_handler، وينفّذ استعلام عند استدعاء handler.
    • query_param_name — يُستخدم مع النوع dynamic_query_handler، ويستخرج وينفّذ القيمة المقابلة لقيمة query_param_name في معلمات طلب HTTP.
    • status — يُستخدم مع النوع static، وهو رمز حالة الاستجابة.
    • content_type — يُستخدم مع أي type، وهو content-type للاستجابة.
    • http_response_headers — يُستخدم مع أي type، وهو map لـ headers الخاصة بالاستجابة. ويمكن استخدامه أيضًا لتعيين نوع المحتوى.
    • response_content — يُستخدم مع النوع static، وهو محتوى الاستجابة المُرسَل إلى client. وعند استخدام البادئة 'file://' أو 'config://'، يُؤخذ المحتوى من الملف أو config ويُرسَل إلى client.
    • user - المستخدم الذي يُنفَّذ الاستعلام باسمه (default user هو default). ملاحظة، لا تحتاج إلى تحديد password لهذا المستخدم.

ستُناقش إعدادات الأنواع type المختلفة بعد ذلك.

predefined_query_handler

يدعم predefined_query_handler تعيين قيم Settings وquery_params. ويمكنك ضبط query ضمن النوع predefined_query_handler.

تمثل قيمة query استعلامًا محددًا مسبقًا لـ predefined_query_handler، ويُنفَّذ بواسطة ClickHouse عند مطابقة طلب HTTP ثم تُعاد نتيجة الاستعلام. وهذا إعداد مطلوب.

يوضح المثال التالي قيم إعدادَي max_threads وmax_final_threads، ثم يستعلم جدول النظام للتحقق مما إذا كانت هذه الإعدادات قد ضُبطت بنجاح.

على سبيل المثال:

<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 مرنة يمكنها قبول تنسيقات بيانات متنوعة ومعالجتها داخل استعلاماتك.

على سبيل المثال، يمكنك استخدام _request_body لإنشاء نقطة نهاية REST تقبل بيانات JSON في طلب POST وتُدرجها في جدول:

<http_handlers>
    <rule>
        <methods>POST</methods>
        <url>/api/events</url>
        <handler>
            <type>predefined_query_handler</type>
            <query>
                INSERT INTO events (id, data)
                SELECT {id:UInt32}, {_request_body:String}
            </query>
        </handler>
    </rule>
    <defaults/>
</http_handlers>

يمكنك بعد ذلك إرسال البيانات إلى نقطة النهاية التالية:

curl -X POST 'http://localhost:8123/api/events?id=123' \
  -H 'Content-Type: application/json' \
  -d '{"user": "john", "action": "login", "timestamp": "2024-01-01T10:00:00Z"}'

dynamic_query_handler

في dynamic_query_handler، يُكتب الاستعلام على شكل مُعامل في طلب HTTP. والفرق هو أنه في predefined_query_handler، يُكتب الاستعلام في ملف التهيئة. ويمكن تهيئة query_param_name في dynamic_query_handler.

يستخرج ClickHouse القيمة المقابلة لـ query_param_name من URL الخاص بطلب HTTP ثم ينفّذها. والقيمة الافتراضية لـ 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&param_name_1=max_threads&param_name_2=max_final_threads&query_param=SELECT%20name,value%20FROM%20system.settings%20where%20name%20=%20%7Bname_1:String%7D%20OR%20name%20=%20%7Bname_2:String%7D'
max_threads 1
max_final_threads   2

static

يمكن لـ static إرجاع content_type وstatus وresponse_content. ويمكن أن يعيد response_content المحتوى المحدد.

على سبيل المثال، لإرجاع الرسالة "Say Hi!":

<http_handlers>
        <rule>
            <methods>GET</methods>
            <headers><XXX>xxx</XXX></headers>
            <url>/hi</url>
            <handler>
                <type>static</type>
                <status>402</status>
                <content_type>text/html; charset=UTF-8</content_type>
                <http_response_headers>
                    <Content-Language>en</Content-Language>
                    <X-My-Custom-Header>43</X-My-Custom-Header>
                </http_response_headers>
                <response_content>Say Hi!</response_content>
            </handler>
        </rule>
        <defaults/>
</http_handlers>

يمكن استخدام http_response_headers لتحديد نوع المحتوى بدلًا من content_type.

<http_handlers>
        <rule>
            <methods>GET</methods>
            <headers><XXX>xxx</XXX></headers>
            <url>/hi</url>
            <handler>
                <type>static</type>
                <status>402</status>
                #begin-highlight
                <http_response_headers>
                    <Content-Type>text/html; charset=UTF-8</Content-Type>
                    <Content-Language>en</Content-Language>
                    <X-My-Custom-Header>43</X-My-Custom-Header>
                </http_response_headers>
                #end-highlight
                <response_content>Say Hi!</response_content>
            </handler>
        </rule>
        <defaults/>
</http_handlers>
curl -vv  -H 'XXX:xxx' 'http://localhost:8123/hi'
*   Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /hi HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 402 Payment Required
< Date: Wed, 29 Apr 2020 03:51:26 GMT
< Connection: Keep-Alive
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
* Connection #0 to host localhost left intact
Say Hi!%

اعثر على المحتوى في الإعداد المُرسَل إلى العميل.

<get_config_static_handler><![CDATA[<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>]]></get_config_static_handler>

<http_handlers>
        <rule>
            <methods>GET</methods>
            <headers><XXX>xxx</XXX></headers>
            <url>/get_config_static_handler</url>
            <handler>
                <type>static</type>
                <response_content>config://get_config_static_handler</response_content>
            </handler>
        </rule>
</http_handlers>
$ curl -v  -H 'XXX:xxx' 'http://localhost:8123/get_config_static_handler'
*   Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /get_config_static_handler HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 200 OK
< Date: Wed, 29 Apr 2020 04:01:24 GMT
< Connection: Keep-Alive
< Content-Type: text/plain; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
* Connection #0 to host localhost left intact
<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>%

للعثور على محتوى الملف المُرسَل إلى العميل:

<http_handlers>
        <rule>
            <methods>GET</methods>
            <headers><XXX>xxx</XXX></headers>
            <url>/get_absolute_path_static_handler</url>
            <handler>
                <type>static</type>
                <content_type>text/html; charset=UTF-8</content_type>
                <http_response_headers>
                    <ETag>737060cd8c284d8af7ad3082f209582d</ETag>
                </http_response_headers>
                <response_content>file:///absolute_path_file.html</response_content>
            </handler>
        </rule>
        <rule>
            <methods>GET</methods>
            <headers><XXX>xxx</XXX></headers>
            <url>/get_relative_path_static_handler</url>
            <handler>
                <type>static</type>
                <content_type>text/html; charset=UTF-8</content_type>
                <http_response_headers>
                    <ETag>737060cd8c284d8af7ad3082f209582d</ETag>
                </http_response_headers>
                <response_content>file://./relative_path_file.html</response_content>
            </handler>
        </rule>
</http_handlers>
$ user_files_path='/var/lib/clickhouse/user_files'
$ sudo echo "<html><body>Relative Path File</body></html>" > $user_files_path/relative_path_file.html
$ sudo echo "<html><body>Absolute Path File</body></html>" > $user_files_path/absolute_path_file.html
$ curl -vv -H 'XXX:xxx' 'http://localhost:8123/get_absolute_path_static_handler'
*   Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /get_absolute_path_static_handler HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 200 OK
< Date: Wed, 29 Apr 2020 04:18:16 GMT
< Connection: Keep-Alive
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
<html><body>Absolute Path File</body></html>
* Connection #0 to host localhost left intact
$ curl -vv -H 'XXX:xxx' 'http://localhost:8123/get_relative_path_static_handler'
*   Trying ::1...
* Connected to localhost (::1) port 8123 (#0)
> GET /get_relative_path_static_handler HTTP/1.1
> Host: localhost:8123
> User-Agent: curl/7.47.0
> Accept: */*
> XXX:xxx
>
< HTTP/1.1 200 OK
< Date: Wed, 29 Apr 2020 04:18:31 GMT
< Connection: Keep-Alive
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Keep-Alive: timeout=10
< X-ClickHouse-Summary: {"read_rows":"0","read_bytes":"0","written_rows":"0","written_bytes":"0","total_rows_to_read":"0","elapsed_ns":"662334","memory_usage":"8451671"}
<
<html><body>Relative Path File</body></html>
* Connection #0 to host localhost left intact

redirect

سيؤدي redirect إلى إعادة توجيه 302 إلى location

على سبيل المثال، إليك كيفية إضافة set user تلقائيًا إلى play في ClickHouse play:

<clickhouse>
    <http_handlers>
        <rule>
            <methods>GET</methods>
            <url>/play</url>
            <handler>
                <type>redirect</type>
                <location>/play?user=play</location>
            </handler>
        </rule>
    </http_handlers>
</clickhouse>

ترويسات استجابة HTTP

يتيح لك ClickHouse تهيئة ترويسات استجابة HTTP مخصّصة يمكن تطبيقها على أي نوع من المعالجات القابلة للتهيئة. ويمكن ضبط هذه الترويسات باستخدام الإعداد http_response_headers، الذي يقبل أزواج مفتاح-قيمة تمثل أسماء الترويسات وقيمها. وتُعد هذه الميزة مفيدة بشكل خاص لتطبيق ترويسات أمان مخصّصة، أو سياسات CORS، أو أي متطلبات أخرى خاصة بترويسات HTTP عبر واجهة ClickHouse HTTP.

على سبيل المثال، يمكنك تهيئة ترويسات من أجل:

  • نقاط نهاية الاستعلام العادية
  • واجهة الويب
  • فحص الحالة.

ومن الممكن أيضًا تحديد common_http_response_headers. وسيتم تطبيقها على جميع معالجات HTTP المعرّفة في التهيئة.

ستُضمَّن هذه الترويسات في استجابة HTTP لكل معالج تم تكوينه.

في المثال أدناه، ستحتوي كل استجابة من الخادم على ترويستين مخصّصتين: X-My-Common-Header و X-My-Custom-Header.

<clickhouse>
    <http_handlers>
        <common_http_response_headers>
            <X-My-Common-Header>Common header</X-My-Common-Header>
        </common_http_response_headers>
        <rule>
            <methods>GET</methods>
            <url>/ping</url>
            <handler>
                <type>ping</type>
                <http_response_headers>
                    <X-My-Custom-Header>Custom indeed</X-My-Custom-Header>
                </http_response_headers>
            </handler>
        </rule>
    </http_handlers>
</clickhouse>

استجابة JSON/XML صالحة عند حدوث استثناء أثناء HTTP streaming

أثناء تنفيذ استعلام عبر HTTP، قد يحدث استثناء بعد إرسال جزء من البيانات بالفعل. وعادةً ما يُرسَل الاستثناء إلى client كنص عادي. وقد يحدث ذلك حتى عند استخدام format بيانات محدد لإخراج البيانات، مما قد يجعل الإخراج غير صالح وفقًا لتنسيق البيانات المحدد. ولتجنّب ذلك، يمكنك استخدام الإعداد 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>
Navigation