F.47. pgsql-http — HTTP-клиент для Tantor SE#
F.47. pgsql-http — HTTP-клиент для Tantor SE
Версия: 1.5.0
F.47.1. Установка
Создать расширение в базе данных Postgres:
CREATE EXTENSION http;
F.47.2. Примеры
URL кодирование строки.
SELECT urlencode('my special string''s & things?');
urlencode
-------------------------------------
my+special+string%27s+%26+things%3F
(1 row)
URL кодирование ассоциативного массива JSON.
SELECT urlencode(jsonb_build_object('name','Colin & James','rate','50%'));
urlencode
-------------------------------------
name=Colin+%26+James&rate=50%25
(1 row)
Выполните GET-запрос и просмотрите содержимое.
SELECT content
FROM http_get('http://httpbin.org/ip');
content
-----------------------------
{"origin":"24.69.186.43"}
(1 row)
Выполните GET-запрос с заголовком Authorization.
SELECT content::json->'headers'->>'Authorization'
FROM http((
'GET',
'http://httpbin.org/headers',
ARRAY[http_header('Authorization','Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9')],
NULL,
NULL
)::http_request)
content
----------------------------------------------
Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
(1 row)
Прочитайте поля status и content из объекта http_response.
SELECT status, content_type
FROM http_get('http://httpbin.org/');
status | content_type
--------+--------------------------
200 | text/html; charset=utf-8
(1 row)
Показать все заголовки http_header в объекте http_response.
SELECT (unnest(headers)).*
FROM http_get('http://httpbin.org/');
field | value
----------------------------------+-------------------------------
Connection | close
Server | meinheld/0.6.1
Date | Tue, 09 Jan 2018 18:40:30 GMT
Content-Type | text/html; charset=utf-8
Content-Length | 13011
Access-Control-Allow-Origin | *
Access-Control-Allow-Credentials | true
X-Powered-By | Flask
X-Processed-Time | 0.0208520889282
Via | 1.1 vegur
Используйте команду PUT для отправки простого текстового документа на сервер.
SELECT status, content_type, content::json->>'data' AS data
FROM http_put('http://httpbin.org/put', 'some text', 'text/plain');
status | content_type | data
--------+------------------+-----------
200 | application/json | some text
Используйте команду PATCH для отправки простого JSON-документа на сервер.
SELECT status, content_type, content::json->>'data' AS data
FROM http_patch('http://httpbin.org/patch', '{"this":"that"}', 'application/json');
status | content_type | data
--------+------------------+------------------
200 | application/json | '{"this":"that"}'
Используйте команду DELETE для запроса удаления ресурса.
SELECT status, content_type, content::json->>'url' AS url
FROM http_delete('http://httpbin.org/delete');
status | content_type | url
--------+------------------+---------------------------
200 | application/json | http://httpbin.org/delete
В качестве ярлыка для отправки данных в GET-запросе передайте аргумент данных JSONB.
SELECT status, content::json->'args' AS args
FROM http_get('http://httpbin.org/get',
jsonb_build_object('myvar','myval','foo','bar'));
Для отправки POST-запроса на URL с использованием данных вместо параметров, встроенных в URL, закодируйте данные в формате JSONB в качестве данных запроса.
SELECT status, content::json->'form' AS form
FROM http_post('http://httpbin.org/post',
jsonb_build_object('myvar','myval','foo','bar'));
Для доступа к двоичному содержимому необходимо преобразовать содержимое из стандартного представления varchar в представление bytea с помощью функции textsend. Использование стандартного приведения varchar::bytea не сработает, так как приведение остановится при обнаружении байта со значением ноль (что часто встречается в двоичных данных).
WITH
http AS (
SELECT * FROM http_get('http://httpbin.org/image/png')
),
headers AS (
SELECT (unnest(headers)).* FROM http
)
SELECT
http.content_type,
length(textsend(http.content)) AS length_binary,
headers.value AS length_headers
FROM http, headers
WHERE field = 'Content-Length';
content_type | length_binary | length_headers --------------+---------------+---------------- image/png | 8090 | 8090
Для доступа только к заголовкам вы можете выполнить HEAD-запрос. Это не будет следовать перенаправлениям.
SELECT
http.status,
headers.value AS location
FROM
http_head('http://google.com') AS http
LEFT OUTER JOIN LATERAL (SELECT value
FROM unnest(http.headers)
WHERE field = 'Location') AS headers
ON true;
status | location
--------+-----------------------------------------------------------
302 | http://www.google.ch/?gfe_rd=cr&ei=ACESWLy_KuvI8zeghL64Ag
F.47.3. Концепции
Каждый HTTP-запрос состоит из http_request и http_response.
Composite type "public.http_request"
Column | Type | Modifiers
--------------+-------------------+-----------
method | http_method |
uri | character varying |
headers | http_header[] |
content_type | character varying |
content | character varying |
Composite type "public.http_response"
Column | Type | Modifiers
--------------+-------------------+-----------
status | integer |
content_type | character varying |
headers | http_header[] |
content | character varying |
Утилитарные функции, http_get(),
http_post(), http_put(),
http_delete() и
http_head() являются просто обертками вокруг основной
функции, http(http_request), которая возвращает
http_response.
Поле headers для запросов и ответов является массивом Tantor SE типа http_header, который представляет собой просто кортеж.
Composite type "public.http_header" Column | Type | Modifiers --------+-------------------+----------- field | character varying | value | character varying |
Как видно из примеров, вы можете развернуть массив кортежей http_header в результирующий набор с помощью функции unnest() массива в Tantor SE. После этого вы выбираете нужный вам заголовок.
F.47.4. Функции
http_header(field VARCHAR, value VARCHAR)возвращаетhttp_headerhttp(request http_request)returnshttp_responsehttp_get(uri VARCHAR)returnshttp_responsehttp_get(uri VARCHAR, data JSONB)возвращаетhttp_responsehttp_post(uri VARCHAR, content VARCHAR, content_type VARCHAR)возвращаетhttp_responsehttp_post(uri VARCHAR, data JSONB)возвращаетhttp_responsehttp_put(uri VARCHAR, content VARCHAR, content_type VARCHAR)возвращаетhttp_responsehttp_patch(uri VARCHAR, content VARCHAR, content_type VARCHAR)возвращаетhttp_responsehttp_delete(uri VARCHAR, content VARCHAR, content_type VARCHAR))возвращаетhttp_responsehttp_head(uri VARCHAR)returnshttp_responsehttp_set_curlopt(curlopt VARCHAR, value varchar)возвращаетbooleanhttp_reset_curlopt()returnsbooleanhttp_list_curlopt()возвращаетsetof(curlopt text, value text)urlencode(string VARCHAR)возвращаетtexturlencode(data JSONB)возвращаетtext
F.47.5. Опции CURL
Выберите опции CURL, доступные для установки с помощью функции http_set_curlopt(curlopt VARCHAR, value varchar).
Например,
-- Set the PROXYPORT option
SELECT http_set_curlopt('CURLOPT_PROXYPORT', '12345');
-- List all currently set options
SELECT * FROM http_list_curlopt();
Установит опцию порта прокси для времени жизни соединения с базой данных. Вы можете сбросить все опции CURL до их значений по умолчанию, используя функцию http_reset_curlopt().
Использование этого расширения в качестве фонового автоматизированного процесса без надзора (например, в качестве триггера) может иметь непредвиденные последствия для других серверов. Считается хорошей практикой предоставлять контактную информацию в своих запросах, чтобы администраторы могли связаться с вами в случае выхода ваших HTTP-вызовов из-под контроля.
Определенные политики API (например, политика User-Agent Викимедиа) могут требовать даже обмена определенной контактной информацией с каждым запросом. Другие могут запрещать (с помощью robots.txt) определенным агентам, которых они не распознают.
Для таких случаев можно установить опцию CURLOPT_USERAGENT.
SELECT http_set_curlopt('CURLOPT_USERAGENT',
'Examplebot/2.1 (+http://www.example.com/bot.html) Contact abuse@example.com');
SELECT status, content::json ->> 'user-agent' FROM http_get('http://httpbin.org/user-agent');
status | user_agent
--------+-----------------------------------------------------------
200 | Examplebot/2.1 (+http://www.example.com/bot.html) Contact abuse@example.com
F.47.6. Сохранение активности и таймауты
Рекомендуется использовать подход http_reset_curlopt(),
описанный выше. Глобальные переменные, перечисленные ниже, будут
устаревать и постепенно удаляться.
По умолчанию каждый запрос использует новое соединение и гарантирует, что соединение закрывается, когда запрос завершается. Это поведение снижает вероятность использования системных ресурсов (сокетов), поскольку расширение работает в течение продолжительного времени.
Высокопроизводительные приложения могут захотеть включить keep-alive и сохранение соединения для снижения задержки и увеличения пропускной способности. Следующая переменная GUC изменяет поведение расширения http для поддержки соединений как можно дольше:
http.keepalive = 'on'
По умолчанию установлен временный тайм-аут выполнения запроса в 5 секунд. Если требуется другое время ожидания, можно использовать следующую переменную GUC для его установки в миллисекундах:
http.timeout_msec = 200
F.47.7. Почему это плохая идея
“Что произойдет, если веб-страница займет много времени для возврата?” Ваш SQL-запрос просто будет ждать, пока это не произойдет. Убедитесь, что ваш веб-сервис быстро отказывает. Или (опасно по-другому) выполните ваш запрос в pg_background.
“Что если веб-страница возвращает мусор?” Ваш SQL-запрос должен проверить наличие мусора перед выполнением каких-либо действий с данными.
“Что если веб-страница никогда не вернется?” Установите короткий таймаут, или отправьте отмену запроса, или просто ждите бесконечно.
“Что, если пользователь запрашивает страницу, которую не следует запрашивать?” Ограничьте доступ к функциям или просто не устанавливайте такое расширение, где пользователи могут получить к нему доступ.