F.47. pgsql-http PostgreSQL HTTP клиент#

F.47. pgsql-http PostgreSQL HTTP клиент

F.47. pgsql-http PostgreSQL HTTP клиент

F.47.1. О pgsql-http

Версия: 1.5.0

GitHub

Установка: 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 в набор результатов, используя Tantor SE unnest() функция на массиве. Оттуда вы выбираете конкретный заголовок, который вас интересует.

F.47.4. Функции

  • http_header(field VARCHAR, value VARCHAR) возвращает http_header

  • http(request http_request) returns http_response

  • http_get(uri VARCHAR) returns http_response

  • http_get(uri VARCHAR, data JSONB) возвращает http_response

  • http_post(uri VARCHAR, content VARCHAR, content_type VARCHAR) возвращает http_response

  • http_post(uri VARCHAR, data JSONB) возвращает http_response

  • http_put(uri VARCHAR, content VARCHAR, content_type VARCHAR) возвращает http_response

  • http_patch(uri VARCHAR, content VARCHAR, content_type VARCHAR) возвращает http_response

  • http_delete(uri VARCHAR, content VARCHAR, content_type VARCHAR)) возвращает http_response

  • http_head(uri VARCHAR) returns http_response

  • http_set_curlopt(curlopt VARCHAR, value varchar) возвращает boolean

  • http_reset_curlopt() returns boolean

  • http_list_curlopt() возвращает setof(curlopt text, value text)

  • urlencode(string VARCHAR) возвращает text

  • urlencode(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 [email protected]');

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 [email protected]

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-запрос должен проверить наличие мусора перед выполнением каких-либо действий с данными.

  • Что если веб-страница никогда не вернется? Установите короткий таймаут, или отправьте отмену запроса, или просто ждите бесконечно.

  • Что, если пользователь запрашивает страницу, которую не следует запрашивать? Ограничьте доступ к функциям или просто не устанавливайте такое расширение, где пользователи могут получить к нему доступ.