Resource управление

В архитектуре CesiumJS класс Resource представляет универсальный механизм работы с удалёнными ресурсами. Он используется для загрузки изображений, JSON-файлов, тайлов местности, 3D-моделей, текстур, геопространственных данных и любых других сетевых ресурсов.

Практически все высокоуровневые компоненты CesiumJS в той или иной форме используют Resource. Через него осуществляется:

  • формирование URL-адресов;
  • управление параметрами запросов;
  • настройка HTTP-заголовков;
  • работа с прокси-серверами;
  • повторные попытки загрузки;
  • получение различных типов данных;
  • контроль сетевого взаимодействия.

Класс расположен в пространстве имён Cesium.Resource.


Создание объекта Resource

Базовый способ создания ресурса предполагает передачу URL.

const resource = new Cesium.Resource({
    url: "https://example.com/data.json"
});

Также допускается сокращённая форма:

const resource = new Cesium.Resource(
    "https://example.com/data.json"
);

После создания объект хранит всю информацию, необходимую для выполнения запросов.


Свойство url

Основное свойство объекта — url.

const resource = new Cesium.Resource({
    url: "https://server.com/tiles"
});

console.log(resource.url);

Результат:

https://server.com/tiles

URL может быть как абсолютным, так и относительным.

const resource = new Cesium.Resource({
    url: "./assets/model.glb"
});

Формирование URL с параметрами

Очень часто серверные сервисы требуют передачи параметров запроса.

Например:

https://server.com/data?id=25&type=city

Вместо ручной сборки строки рекомендуется использовать queryParameters.

const resource = new Cesium.Resource({
    url: "https://server.com/data",
    queryParameters: {
        id: 25,
        type: "city"
    }
});

Получаемый URL:

https://server.com/data?id=25&type=city

Такой подход уменьшает вероятность ошибок и автоматически выполняет экранирование специальных символов.


Добавление параметров после создания

Параметры можно изменять динамически.

const resource = new Cesium.Resource({
    url: "https://server.com/data"
});

resource.setQueryParameters({
    page: 5
});

URL станет:

https://server.com/data?page=5

Добавление новых параметров:

resource.setQueryParameters({
    limit: 100
});

Результат:

https://server.com/data?page=5&limit=100

Замена параметров

Для полной замены существующих параметров используется второй аргумент.

resource.setQueryParameters(
    {
        category: "buildings"
    },
    true
);

Теперь старые параметры будут удалены.


Работа с шаблонными URL

Во многих картографических сервисах используются шаблоны.

Пример:

https://server.com/tiles/{z}/{x}/{y}.png

Для формирования итогового адреса применяются шаблонные значения.

const resource = new Cesium.Resource({
    url: "https://server.com/tiles/{z}/{x}/{y}.png"
});

resource.setTemplateValues({
    z: 5,
    x: 12,
    y: 7
});

Получаем:

https://server.com/tiles/5/12/7.png

Заголовки HTTP

Многие API требуют передачу дополнительных заголовков.

Например:

const resource = new Cesium.Resource({
    url: "https://api.example.com/data",
    headers: {
        Authorization: "Bearer token123",
        Accept: "application/json"
    }
});

Cesium автоматически добавит указанные заголовки к запросу.


Изменение заголовков после создания

Заголовки можно обновлять динамически.

resource.headers["Authorization"] =
    "Bearer newToken";

Либо:

resource.headers = {
    Authorization: "Bearer abc",
    Accept: "application/json"
};

Получение производного ресурса

Одной из наиболее полезных возможностей является создание дочерних ресурсов.

Метод getDerivedResource()

Предположим, существует базовый адрес:

const api = new Cesium.Resource({
    url: "https://api.example.com/"
});

Создание дочернего ресурса:

const users = api.getDerivedResource({
    url: "users"
});

Результат:

https://api.example.com/users

Другой пример:

const posts = api.getDerivedResource({
    url: "posts"
});

Результат:

https://api.example.com/posts

Подход особенно полезен при работе с REST API.


Получение JSON

Для загрузки JSON предусмотрен метод fetchJson().

resource.fetchJson()
    .then(data => {
        console.log(data);
    });

Эквивалентный HTTP-запрос:

GET /data.json

Возвращаемое значение — Promise.


Асинхронный синтаксис

На практике удобнее использовать async/await.

async function loadData() {
    const data = await resource.fetchJson();

    console.log(data);
}

Получение текстовых данных

Для текстовых файлов применяется fetchText().

const resource = new Cesium.Resource({
    url: "notes.txt"
});

const text = await resource.fetchText();

console.log(text);

Получение бинарных данных

Для загрузки двоичных файлов используется fetchArrayBuffer().

const resource = new Cesium.Resource({
    url: "model.glb"
});

const buffer =
    await resource.fetchArrayBuffer();

Такой подход широко используется при работе с:

  • glTF;
  • 3D Tiles;
  • пользовательскими форматами данных;
  • текстурами.

Получение Blob-объектов

Метод:

fetchBlob()

Пример:

const blob =
    await resource.fetchBlob();

Возвращается объект Blob, пригодный для дальнейшей обработки браузером.


Загрузка изображений

Для изображений используется специальный метод.

const image =
    await resource.fetchImage();

После получения объект можно использовать самостоятельно.

document.body.appendChild(image);

Настройка параметров изображения

Дополнительные параметры:

resource.fetchImage({
    flipY: true
});

Или:

resource.fetchImage({
    preferImageBitmap: true
});

Подобные настройки особенно полезны при работе с WebGL.


Выполнение произвольного запроса

Иногда встроенных методов недостаточно.

Для таких случаев существует fetch().

resource.fetch({
    responseType: "json"
});

Пример:

const result = await resource.fetch({
    method: "POST"
});

POST-запросы

Передача данных серверу:

const resource = new Cesium.Resource({
    url: "https://api.example.com/create"
});

await resource.fetch({
    method: "POST",
    data: JSON.stringify({
        name: "Building",
        floors: 20
    })
});

PUT-запросы

await resource.fetch({
    method: "PUT",
    data: JSON.stringify({
        id: 1,
        name: "Updated"
    })
});

DELETE-запросы

await resource.fetch({
    method: "DELETE"
});

Работа с прокси

Некоторые сервисы требуют промежуточного прокси-сервера.

Cesium предоставляет класс DefaultProxy.

const proxy =
    new Cesium.DefaultProxy("/proxy/");

Подключение:

const resource = new Cesium.Resource({
    url: "https://external-server.com/data",
    proxy: proxy
});

Все запросы будут автоматически проходить через прокси.


Повторные попытки загрузки

Сетевые ошибки неизбежны, особенно при работе с глобальными геоданными.

Для автоматического повторения запросов используется механизм retry.

const resource = new Cesium.Resource({
    url: "https://server.com/data"
});

Настройка:

resource.retryAttempts = 3;

Теперь Cesium сможет выполнить до трёх повторных попыток.


Функция retryCallback

Логика повтора полностью настраивается.

resource.retryCallback = function(error) {

    console.log(error);

    return Promise.resolve(true);
};

Возврат:

true

означает повтор запроса.

Возврат:

false

означает окончательное завершение операции.


Пример интеллектуального повтора

resource.retryAttempts = 5;

resource.retryCallback = function(error) {

    if (error.statusCode === 503) {
        return Promise.resolve(true);
    }

    return Promise.resolve(false);
};

Повтор будет происходить только при временной недоступности сервера.


Работа с кредитами данных

Некоторые поставщики картографической информации требуют обязательного отображения авторства.

Для этого используется свойство credits.

const resource = new Cesium.Resource({
    url: "https://provider.com/data"
});

При использовании провайдеров Cesium автоматически извлекает и отображает необходимые кредиты.


Проверка абсолютного URL

Метод:

resource.isDataUri

Позволяет определить, используется ли Data URI.

Пример:

const resource = new Cesium.Resource({
    url: "data:image/png;base64,..."
});

console.log(resource.isDataUri);

Результат:

true

Работа с Data URI

Data URI позволяют хранить ресурс непосредственно внутри строки.

const resource = new Cesium.Resource({
    url: "dat a:text/plain;base64,SGVsbG8="
});

Получение содержимого:

const text =
    await resource.fetchText();

Создание ресурса из существующего объекта

Метод:

Cesium.Resource.createIfNeeded()

Удобен для библиотечного кода.

const resource =
    Cesium.Resource.createIfNeeded(
        "https://server.com/data.json"
    );

Если передан URL, будет создан новый объект.

Если передан объект Resource, он будет возвращён без изменений.

const r1 = new Cesium.Resource({
    url: "data.json"
});

const r2 =
    Cesium.Resource.createIfNeeded(r1);

console.log(r1 === r2);

Результат:

true

Типичный сценарий загрузки конфигурации

async function loadConfig() {

    const resource = new Cesium.Resource({
        url: "/config/app.json",
        retryAttempts: 3
    });

    try {

        const config =
            await resource.fetchJson();

        return config;

    } catch(error) {

        console.error(
            "Ошибка загрузки конфигурации",
            error
        );
    }
}

Использование Resource внутри провайдеров данных

Практически все провайдеры Cesium принимают URL, который внутренне преобразуется в Resource.

Например:

const imagery =
    new Cesium.UrlTemplateImageryProvider({
        url:
            "https://tile.openstreetmap.org/{z}/{x}/{y}.png"
    });

Внутри провайдера создаётся объект Resource, который:

  • формирует итоговые URL;
  • управляет параметрами;
  • обрабатывает ошибки;
  • выполняет загрузку тайлов;
  • обеспечивает повторные попытки запросов.

Благодаря этому единый механизм сетевого взаимодействия используется во всей экосистеме CesiumJS.


Практические преимущества использования Resource

Централизация сетевых запросов

  • единый API для всех типов данных;
  • единый механизм обработки ошибок;
  • единый подход к авторизации.

Повторное использование конфигурации

  • базовые URL;
  • общие заголовки;
  • общие параметры запросов.

Удобство масштабирования

  • создание производных ресурсов;
  • поддержка REST API;
  • работа с несколькими серверами данных.

Интеграция с внутренней архитектурой Cesium

  • Imagery Providers;
  • Terrain Providers;
  • 3D Tiles;
  • glTF-ресурсы;
  • пользовательские источники данных.

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