Перейти к основному содержимому

Remote - HTTP-клиент

Введение​

Часто в наших приложениях нам нужно выполнять HTTP-запросы к внешним сервисам. Это можно сделать с помощью ресурса _remote.

Для выполнения HTTP-вызовов к другим сервисам или внутренним серверам на компьютере, либо для вызова какого-либо сервиса в интернете, использование ресурса Remote необходимо.

См. документацию ресурса Remote.

Кроме того, мы можем отправлять и получать данные в JSON и выполнять загрузку или скачивание файлов.

Инициализация​

Чтобы выполнить HTTP-вызов, сначала нужно его инициализировать. Для этого используем метод init у _remote и сохраним результат этой операции в переменной с именем remote, чтобы можно было ссылаться на запрос:

// Поддерживает отправку HTTP-параметров
const remoteSimple = _remote.init();
// Поддерживает отправку JSON:
const remoteJSON = _remote.init().asJSON();

Конфигурация​

Также мы можем задать глобальные настройки в приложении; обратите внимание на этот полный пример:

...
"remote": {
"example-basic-auth": {
"url": "https://example.com/api/rest/example",
"form": true,
"authorization": {
"username": "admin",
"password": "pass"
},
"data": {
"param1": "value 1...",
"param2": "value 2..."
}
},
"example-auth-token": {
"urlPrefix": "https://example.com/api",
"json": true,
"authorization": "Bearer AUTH-TOKEN-HERE",
"connectTimeout": 5000,
"readTimeout": 60000,
}
},
...

Мы можем настроить префикс URL (urlPrefix) или полный URL (url).

Мы можем определить, должны ли запросы по умолчанию отправлять данные в виде формы или JSON.

Поддерживается отправка базовой авторизации с логином и паролем или токеном.

Также можно задать данные по умолчанию, которые будут отправляться (data), и предельные таймауты соединения (connectTimeout) и чтения (readTimeout).

Как использовать​

Чтобы использовать ресурс Remote с настройками, определёнными в приложении, достаточно инициализировать ресурс с ключом конфигурации, например:

const response = _remote.init("example-basic-auth").post();

А если определён URL префикса:

const remote = _remote.init("example-auth-token");
const response = remote.post(
"/services/load-data",
_val.map()
.set("param1", "value 1")
.set("param2", "value 2")
);

HTTP-запрос​

Посмотрите, как можно инициировать HTTP-запрос с помощью ресурса Remote.

Отправка JSON​

Чтобы отправлять данные в формате JSON, нужно указать тип содержимого как JSON:

Простой способ сделать это — использовать метод asJSON(), например:

const remote = _remote.init().asJSON();
remote.setURL("http://example.com/save");
const response = remote.post(
_val.map()
.set("data", "example")
.set("json", true)
);

Таким образом данные будут отправляться как JSON для HTTP-методов POST и PUT, но для GET и DELETE данные всегда отправляются в строке запроса, поскольку для этих методов протокол HTTP не поддерживает наличие тела с данными.

HTTP-методы​

Нам не нужно явно указывать HTTP-метод в заголовке вызова; для этого наша ссылка на вызов имеет собственную функцию для каждого типа HTTP-метода:

const remote = _remote.init();

remote.setURL("http://example.com");

remote.get(); // для GET-запросов
remote.post(); // для POST-запросов
remote.put(); // для PUT-запросов
remote.delete(); // для DELETE-запросов

HTTP-заголовок​

Чтобы настроить параметры HTTP-заголовка, можно задать ключи с помощью метода getHeader(), например:

const remote = _remote.init();

remote.getHeader().set("KEY", "VALUE");

URL запроса​

Чтобы указать URL запроса, достаточно передать его первым параметром в функции соответствующего HTTP-метода:

const remote = _remote.init().asJSON()

remote.get("http://example.com") // для GET-запросов
remote.post("http://example.com") // для POST-запросов
remote.put("http://example.com") // для PUT-запросов
remote.delete("http://example.com") // для DELETE-запросов

Добавление данных в запрос​

Если нужно добавить данные в тело запроса, достаточно передать их вторым параметром в функцию соответствующего метода:

const remote = _remote.init().asJSON();

remote.get("http://example.com", _val.map().set("user_id", 1)); // для GET-запросов
remote.post("http://example.com", _val.map().set("user_id", 1)); // для POST-запросов
remote.put("http://example.com", _val.map().set("user_id", 1)); // для PUT-запросов
remote.delete("http://example.com", _val.map().set("user_id", 1)); // для DELETE-запросов

Ответ​

После получения ответа на запрос мы можем прочитать его данные с помощью метода json или content:

const remote = _remote.init().asJSON();

const response = remote.post(
"http://example.com",
_val.map().set("user_id", 1)
);

if (response.ok()) {
_log.info("Ответ в формате JSON", response.json());
} else {
_log.info("Ошибка со статусом: "+ response.statusCode(), response.content());
}

В ответе с помощью функции json() мы получаем массив или объект, предоставленный как Values, а с помощью функции content() получаем сырое текстовое содержимое или HTML; номер полученного кода состояния возвращается в statusCode(), при этом ok() возвращает булево значение, истинное, если код состояния находится в диапазоне от 200 до 299.

Скачивание​

Чтобы скачивать файлы, используем remote с asBinary(), чтобы указать, что должна быть двоичная передача.

Посмотрите этот пример полного сервиса:

server/services/file-download.js
const download = _remote.asBinary()
.get('https://raw.githubusercontent.com/netuno-org/platform/main/docs/images/overview.png');

if (!download.ok()) {
_log.error(`Статус скачивания файла: ${download.statusCode()}\n${download.toString()}`);
_header.status(500);
_out.json({result: false, error: 'file-download-failed'});
_exec.stop();
}

const file = download.file();
_log.info(`Имя скачанного файла: ${file.name()}`);

file.save(_app.file(`storage/filesystem/server/${file.name()}`));
file.save(_storage.filesystem("server", "other.png").file());
file.save(_os.file("/tmp/download.png"));
_out.json({result: true});

Метод file.save используется 3 раза намеренно; чтобы узнать больше о _app.file, _storage и _os.file, см. руководство по работе с файлами и папками.

Загрузка​

Чтобы отправить структурированный файл как форму в формате multipart, используем asMultipartFormData().

Посмотрите полный пример сервиса:

server/services/file-upload.js
const file = _app.file("public/images/logo.png");

const upload = _remote.asMultipartFormData()
.post(
'http://localhost:9000/services/file-receiver',
_val.map()
.set("file", file)
);

if (upload.ok()) {
_log.info(`Успешно загружено: ${file.name()}`);
_out.json({result: true});
} else {
_log.error(`Статус загрузки файла: ${upload.statusCode()}\n${upload.toString()}`);
_header.status(500);
_out.json({result: false, error: 'file-upload-failed'});
}

Обратите внимание, что в примере выше файл отправляется в другой сервис; посмотрите, как этот другой сервис, принимающий файл, может быть реализован в Netuno:

server/services/file-receiver.js
const file = _req.getFile("file");
_log.info(`Имя полученного файла: ${file.name()}`);
file.save(_storage.filesystem("server", "received.png").file());
_out.json({result: true});

Заключение​

С помощью ресурса Remote мы можем интегрировать внешние API, экспортировать, импортировать или синхронизировать данные.

Кроме того, мы можем интегрировать сервисы, реализованные на других технологиях, что позволяет выполнять специфические операции, предоставляемые другими языками.