Remote - HTTP-клиент
Введение
Часто в наших приложениях нам нужно выполнять HTTP-запросы к внешним сервисам. Это можно сделать с помощью ресурса _remote.
Для выполнения HTTP-вызовов к другим сервисам или внутренним серверам на компьютере, либо для вызова какого-либо сервиса в интернете, использование ресурса Remote необходимо.
См. документацию ресурса Remote.
Кроме того, мы можем отправлять и получать данные в JSON и выполнять загрузку или скачивание файлов.
Инициализация
Чтобы выполнить HTTP-вызов, сначала нужно его инициализировать. Для этого используем метод init у _remote и сохраним результат этой операции в переменной с именем remote, чтобы можно было ссылаться на запрос:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
// Поддерживает отправку HTTP-параметров
const remoteSimple = _remote.init();
// Поддерживает отправку JSON:
const remoteJSON = _remote.init().asJSON();
// Поддерживает отправку HTTP-параметров
const remoteSimple = _remote.init();
// Поддерживает отправку JSON:
const remoteJSON = _remote.init().asJSON();
# Поддерживает отправку HTTP-параметров
remoteSimple = _remote.init()
# Поддерживает отправку JSON:
remoteJSON = _remote.init().asJSON()
# Поддерживает отправку HTTP-параметров
remoteSimple = _remote.init()
# Поддерживает отправку JSON:
remoteJSON = _remote.init().asJSON()
// Поддерживает отправку HTTP-параметров
val remoteSimple = _remote.init()
// Поддерживает отправку JSON:
val remoteJSON = _remote.init().asJSON()
// Поддерживает отправку HTTP-параметров
final remoteSimple = _remote.init()
// Поддерживает отправку JSON:
final 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 с настройками, определёнными в приложении, достаточно инициализировать ресурс с ключом конфигурации, например:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
const response = _remote.init("example-basic-auth").post();
const response = _remote.init("example-basic-auth").post();
response = _remote.init("example-basic-auth").post()
response = _remote.init("example-basic-auth").post()
val response = _remote.init("example-basic-auth").post()
final response = _remote.init("example-basic-auth").post()
А если определён URL префикса:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
const remote = _remote.init("example-auth-token");
const response = remote.post(
"/services/load-data",
_val.map()
.set("param1", "value 1")
.set("param2", "value 2")
);
const remote = _remote.init("example-auth-token");
const response = remote.post(
"/services/load-data",
_val.map()
.set("param1", "value 1")
.set("param2", "value 2")
);
remote = _remote.init("example-auth-token")
response = remote.post(
"/services/load-data",
_val.map()
.set("param1", "value 1")
.set("param2", "value 2")
)
remote = _remote.init("example-auth-token")
response = remote.post(
"/services/load-data",
_val.map()
.set("param1", "value 1")
.set("param2", "value 2")
)
val remote = _remote.init("example-auth-token")
val response = remote.post(
"/services/load-data",
_val.map()
.set("param1", "value 1")
.set("param2", "value 2")
)
final remote = _remote.init("example-auth-token")
final response = remote.post(
"/services/load-data",
_val.map()
.set("param1", "value 1")
.set("param2", "value 2")
)
HTTP-запрос
Посмотрите, как можно инициировать HTTP-запрос с помощью ресурса Remote.
Отправка JSON
Чтобы отправлять данные в формате JSON, нужно указать тип содержимого как JSON:
Простой способ сделать это — использовать метод asJSON(), например:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
const remote = _remote.init().asJSON();
remote.setURL("http://example.com/save");
const response = remote.post(
_val.map()
.set("data", "example")
.set("json", true)
);
const remote = _remote.init().asJSON();
remote.setURL("http://example.com/save");
const response = remote.post(
_val.map()
.set("data", "example")
.set("json", true)
);
remote = _remote.init().asJSON()
remote.setURL("http://example.com/save")
response = remote.post(
_val.map()
.set("data", "example")
.set("json", true)
)
remote = _remote.init().asJSON()
remote.setURL("http://example.com/save")
response = remote.post(
_val.map()
.set("data", "example")
.set("json", true)
)
val remote = _remote.init().asJSON()
remote.setURL("http://example.com/save")
val response = remote.post(
_val.map()
.set("data", "example")
.set("json", true)
)
final remote = _remote.init().asJSON()
remote.setURL("http://example.com/save")
final response = remote.post(
_val.map()
.set("data", "example")
.set("json", true)
)
Таким образом данные будут отправляться как JSON для HTTP-методов POST и PUT, но для GET и DELETE данные всегда отправляются в строке запроса, поскольку для этих методов протокол HTTP не поддерживает наличие тела с данными.
HTTP-методы
Нам не нужно явно указывать HTTP-метод в заголовке вызова; для этого наша ссылка на вызов имеет собственную функцию для каждого типа HTTP-метода:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
const remote = _remote.init();
remote.setURL("http://example.com");
remote.get(); // для GET-запросов
remote.post(); // для POST-запросов
remote.put(); // для PUT-запросов
remote.delete(); // для DELETE-запросов
const remote = _remote.init();
remote.setURL("http://example.com");
remote.get(); // для GET-запросов
remote.post(); // для POST-запросов
remote.put(); // для PUT-запросов
remote.delete(); // для DELETE-запросов
remote = _remote.init()
remote.setURL("http://example.com")
remote.get() # для GET-запросов
remote.post() # для POST-запросов
remote.put() # для PUT-запросов
remote.delete() # для DELETE-запросов
remote = _remote.init()
remote.setURL("http://example.com")
remote.get() # для GET-запросов
remote.post() # для POST-запросов
remote.put() # для PUT-запросов
remote.delete() # для DELETE-запросов
val remote = _remote.init()
remote.setURL("http://example.com")
remote.get() // для GET-запросов
remote.post() // для POST-запросов
remote.put() // для PUT-запросов
remote.delete() // для DELETE-запросов
final remote = _remote.init()
remote.setURL("http://example.com")
remote.get() // для GET-запросов
remote.post() // для POST-запросов
remote.put() // для PUT-запросов
remote.delete() // для DELETE-запросов
HTTP-заголовок
Чтобы настроить параметры HTTP-заголовка, можно задать ключи с помощью метода getHeader(), например:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
const remote = _remote.init();
remote.getHeader().set("KEY", "VALUE");
const remote = _remote.init();
remote.getHeader().set("KEY", "VALUE");
remote = _remote.init()
remote.getHeader().set("KEY", "VALUE")
remote = _remote.init()
remote.getHeader().set("KEY", "VALUE")
val remote = _remote.init()
remote.getHeader().set("KEY", "VALUE")
final 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-запросов
Добавление данных в запрос
Если нужно добавить данные в тело запроса, достаточно передать их вторым параметром в функцию соответствующего метода:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
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-запросов
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-запросов
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-запросов
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-запросов
val 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-запросов
final 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:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
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());
}
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());
}
remote = _remote.init().asJSON()
response = remote.post(
"http://example.com",
_val.map().set("user_id", 1)
)
if response.ok():
_log.info("Ответ в формате JSON", response.json())
else:
_log.info(
f"Ошибка со статусом: {response.statusCode()}",
response.content()
)
remote = _remote.init().asJSON()
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()
)
end
val remote = _remote.init().asJSON()
val 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()
)
}
final remote = _remote.init().asJSON()
final 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(), чтобы указать, что должна быть двоичная передача.
Посмотрите этот пример полного сервиса:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
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});
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});
download = _remote.asBinary().get(
"https://raw.githubusercontent.com/netuno-org/platform/main/docs/images/overview.png"
)
if not download.ok():
_log.error(f"Статус скачивания файла: {download.statusCode()}\n{download.toString()}")
_header.status(500)
_out.json(_val.map().set("result", False).set("error", "file-download-failed"))
_exec.stop()
file = download.file()
_log.info(f"Имя скачанного файла: {file.name()}")
file.save(_app.file(f"storage/filesystem/server/{file.name()}"))
file.save(_storage.filesystem("server", "other.png").file())
file.save(_os.file("/tmp/download.png"))
_out.json(_val.map().set("result", True))
download = _remote.asBinary().get(
"https://raw.githubusercontent.com/netuno-org/platform/main/docs/images/overview.png"
)
unless download.ok()
_log.error("Статус скачивания файла: #{download.statusCode()}\n#{download.toString()}")
_header.status(500)
_out.json(_val.map().set("result", false).set("error", "file-download-failed"))
_exec.stop()
end
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(_val.map().set("result", true))
val 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(_val.map().set("result", false).set("error", "file-download-failed"))
_exec.stop()
}
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(_val.map().set("result", true))
final 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()
}
final 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().
Посмотрите полный пример сервиса:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
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'});
}
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'});
}
file = _app.file("public/images/logo.png")
upload = _remote.asMultipartFormData().post(
"http://localhost:9000/services/file-receiver",
_val.map().set("file", file)
)
if upload.ok():
_log.info(f"Успешно загружено: {file.name()}")
_out.json(_val.map().set("result", True))
else:
_log.error(f"Статус загрузки файла: {upload.statusCode()}\n{upload.toString()}")
_header.status(500)
_out.json(_val.map().set("result", False).set("error", "file-upload-failed"))
file = _app.file("public/images/logo.png")
upload = _remote.asMultipartFormData().post(
"http://localhost:9000/services/file-receiver",
_val.map().set("file", file)
)
if upload.ok()
_log.info("Успешно загружено: #{file.name()}")
_out.json(_val.map().set("result", true))
else
_log.error("Статус загрузки файла: #{upload.statusCode()}\n#{upload.toString()}")
_header.status(500)
_out.json(_val.map().set("result", false).set("error", "file-upload-failed"))
end
val file = _app.file("public/images/logo.png")
val upload = _remote.asMultipartFormData().post(
"http://localhost:9000/services/file-receiver",
_val.map().set("file", file)
)
if (upload.ok()) {
_log.info("Успешно загружено: ${file.name()}")
_out.json(_val.map().set("result", true))
} else {
_log.error("Статус загрузки файла: ${upload.statusCode()}\n${upload.toString()}")
_header.status(500)
_out.json(_val.map().set("result", false).set("error", "file-upload-failed"))
}
final file = _app.file("public/images/logo.png")
final 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:
- JavaScript
- TypeScript
- Python
- Ruby
- Kotlin
- Groovy
const file = _req.getFile("file");
_log.info(`Имя полученного файла: ${file.name()}`);
file.save(_storage.filesystem("server", "received.png").file());
_out.json({result: true});
const file = _req.getFile("file");
_log.info(`Имя полученного файла: ${file.name()}`);
file.save(_storage.filesystem("server", "received.png").file());
_out.json({result: true});
file = _req.getFile("file")
_log.info(f"Имя полученного файла: {file.name()}")
file.save(_storage.filesystem("server", "received.png").file())
_out.json(_val.map().set("result", True))
file = _req.getFile("file")
_log.info("Имя полученного файла: #{file.name()}")
file.save(_storage.filesystem("server", "received.png").file())
_out.json(_val.map().set("result", true))
val file = _req.getFile("file")
_log.info("Имя полученного файла: ${file.name()}")
file.save(_storage.filesystem("server", "received.png").file())
_out.json(_val.map().set("result", true))
final file = _req.getFile("file")
_log.info(`Имя полученного файла: ${file.name()}`)
file.save(_storage.filesystem("server", "received.png").file())
_out.json({result: true})
Заключение
С помощью ресурса Remote мы можем интегрировать внешние API, экспортировать, импортировать или синхронизировать данные.
Кроме того, мы можем интегрировать сервисы, реализованные на других технологиях, что позволяет выполнять специфические операции, предоставляемые другими языками.