Доброго времени суток!
Хочу познакомить вас с библиотекой dlang-requests. Для чего она? Для D она хочет быть тем-же, чем python-requests является для python, то есть — удобным http-(и ftp) клиентом. Автор клялся, что при написании библиотеки его целями были:
Первая часть статьи будет состоять из примеров использования dlang-requests для наиболее часто встречающихся задач.
Cоздадим самое простое приложение, использующее dlang-requests (делайте копипаст прямо в шелл если вы под юникс-подобной осью):
Пока всё просто: в случае, если вам нужно только содержание документа, вы можете использовать getContent(url). Этот вызов просто вернет вам буфер с документом.
Почему буфер а не просто массив байт? Потому что в большинстве случаев в буфере будут находиться данные полученные непосредственно из сети, без лишних копирований и сборки строк из кусочков. Если вам нужно — буфер легко превращается в массив байт с помощью метода data():
Но нужно ли вам это? Ведь буфер поддерживает множество примитивов Range, и вы можете использовать его напрямую для передачи в соответствующие алгоритмы. Например, нам не нужно преобразовывать контент в string для того, что-бы подсчитать число строк в ответе, поскольку
Eще пример: мы можем без дополнительных усилий распарсить полученный json:
Перед тем как разобраться с post, посмотрим что делать если нам нужен get с параметрами.
Первый и самый простой post это post в веб-форму, используя form-urlencoded. Такой post используется обычно для передачи небольших объемов данных и по виду вызова напоминает вызов get c параметрами:
Обратите внимание: вызов getContent превратился в postContent, больше ничего не изменилось.
Multipart form POST — служит для передачи на сервер бОльших обьемов данных, в том числе для аплоада файлов через веб-форму.
Мы собираем поля для отправки в форму с помощью вызова form.add(formData(описание поля)) где первым параметром для formData будет имя поля, а вторым — либо массив с отправляемыми данными, либо открытый на чтение файл. Третим параметром может быть ассоциативный массив с дополнительными данными (в том числе Content-type для отправляемой части).
Наконец, последним вариантом вызова postContent, является отправка данных минуя всякие формы. Здесь возможны два варианта. Первый — отправка однорангового массива данных (например ubyte[]). В этом случае мы в момент вызова должны знать длину массива, поскольку при передаче используется заголовок Content-Length. Я приведу здесь только строку вызова:
В случае если мы по какой-либо причине не знаем длину массива в момент вызова (но знаем что она конечна) можно использовать передачу массива размерности 2, в этом случае каждый последовательный кусочек массива будет передан как очередной chunk в Transfer-Encoding: chunked:
На этом заканчивается обзор самого простого использования dlang-requests — когда вам не нужна отладка, не нужнен стриминг получаемого ответа, не нужны никакие методы кроме GET и POST. Всё, что не рассмотрели в части 1, рассмотрим в части 2.
Ссылка на репозиторий проекта на github.
Удачи!
Хочу познакомить вас с библиотекой dlang-requests. Для чего она? Для D она хочет быть тем-же, чем python-requests является для python, то есть — удобным http-(и ftp) клиентом. Автор клялся, что при написании библиотеки его целями были:
- удобный, простой интерфейс
- производительность сопоставимая с libcurl
- сочетаемость со стандартной библиотекой D
Первая часть статьи будет состоять из примеров использования dlang-requests для наиболее часто встречающихся задач.
Начнем с запросов GET
Cоздадим самое простое приложение, использующее dlang-requests (делайте копипаст прямо в шелл если вы под юникс-подобной осью):
Создаем минимальное приложение c помощью dub
В результате выполнения команды dub run в консоли должен нарисоваться html, вытянутый из корня сайта httpbin.org.
mkdir test-requests && cd test-requests && dub init . requests
cat >source/app.d<<EOF
import std.stdio;
import requests;
void main()
{
writeln(getContent("http://httpbin.org"));
}
EOF
dub run
Пока всё просто: в случае, если вам нужно только содержание документа, вы можете использовать getContent(url). Этот вызов просто вернет вам буфер с документом.
Почему буфер а не просто массив байт? Потому что в большинстве случаев в буфере будут находиться данные полученные непосредственно из сети, без лишних копирований и сборки строк из кусочков. Если вам нужно — буфер легко превращается в массив байт с помощью метода data():
преобразуем ответ в массив байт
import std.stdio;
import requests;
void main()
{
auto content = getContent("http://httpbin.org");
writeln(typeid(content.data()));
}
Но нужно ли вам это? Ведь буфер поддерживает множество примитивов Range, и вы можете использовать его напрямую для передачи в соответствующие алгоритмы. Например, нам не нужно преобразовывать контент в string для того, что-бы подсчитать число строк в ответе, поскольку
ответ может быть обработан алгоритмами стандарной библиотеки, работающими с range, (заодно смотрим какими свойствами обладает ответ)
import std.stdio;
import std.range.primitives;
import std.algorithm;
import requests;
void main()
{
auto content = getContent("http://httpbin.org");
writeln(content.splitter('\n').count);
alias type = typeof(content);
static assert(isInputRange!type);
static assert(isForwardRange!type);
static assert(hasLength!type);
static assert(hasSlicing!type);
static assert(isBidirectionalRange!type);
static assert(isRandomAccessRange!type);
}Eще пример: мы можем без дополнительных усилий распарсить полученный json:
парсим json из ответа
import std.stdio;
import std.json;
import requests;
void main()
{
auto content = getContent("http://httpbin.org/get");
auto json = parseJSON(content);
writeln(json);
}Перед тем как разобраться с post, посмотрим что делать если нам нужен get с параметрами.
запрашиваем get с параметрами
import std.stdio;
import std.json;
import requests;
void main()
{
auto content = getContent("http://httpbin.org/get",
queryParams("name", "bob", "age", 101));
auto json = parseJSON(content);
writeln(json);
}
Переходим к запросам POST.
Первый и самый простой post это post в веб-форму, используя form-urlencoded. Такой post используется обычно для передачи небольших объемов данных и по виду вызова напоминает вызов get c параметрами:
POST в form-urlencoded
import std.stdio;
import std.json;
import requests;
void main()
{
auto content = postContent("http://httpbin.org/post", queryParams("name", "bob", "age", 101));
auto json = parseJSON(content);
writeln(json);
}Обратите внимание: вызов getContent превратился в postContent, больше ничего не изменилось.
Multipart form POST — служит для передачи на сервер бОльших обьемов данных, в том числе для аплоада файлов через веб-форму.
Пример отправки файла и параметров через MultipartForm
import std.stdio;
import requests;
void main()
{
MultipartForm form;
form.add(formData("content", "example for MultipartForm"));
form.add(formData("file", File("source/app.d", "rb"), ["filename":"app.d", "Content-Type": "text/plain"]));
auto content = postContent("http://httpbin.org/post", form);
writeln(content);
}Мы собираем поля для отправки в форму с помощью вызова form.add(formData(описание поля)) где первым параметром для formData будет имя поля, а вторым — либо массив с отправляемыми данными, либо открытый на чтение файл. Третим параметром может быть ассоциативный массив с дополнительными данными (в том числе Content-type для отправляемой части).
Наконец, последним вариантом вызова postContent, является отправка данных минуя всякие формы. Здесь возможны два варианта. Первый — отправка однорангового массива данных (например ubyte[]). В этом случае мы в момент вызова должны знать длину массива, поскольку при передаче используется заголовок Content-Length. Я приведу здесь только строку вызова:
auto content = postContent("http://httpbin.org/post",
"ABCDEFGH",
"application/binary");
В случае если мы по какой-либо причине не знаем длину массива в момент вызова (но знаем что она конечна) можно использовать передачу массива размерности 2, в этом случае каждый последовательный кусочек массива будет передан как очередной chunk в Transfer-Encoding: chunked:
отправка файла используя Transfer-Encoding: chunked
import std.stdio;
import requests;
void main()
{
auto f = File("source/app.d", "rb");
auto content = postContent("http://httpbin.org/post", f.byChunk(5), "application/binary");
writeln(content);
}На этом заканчивается обзор самого простого использования dlang-requests — когда вам не нужна отладка, не нужнен стриминг получаемого ответа, не нужны никакие методы кроме GET и POST. Всё, что не рассмотрели в части 1, рассмотрим в части 2.
Ссылка на репозиторий проекта на github.
Удачи!
