URL restrictions

Контроль сетевых запросов в Mapbox GL JS играет ключевую роль при интеграции карт в веб-приложения, особенно когда требуется ограничить источники данных, модифицировать URL-запросы или обеспечить безопасную работу с приватными ресурсами. Библиотека активно использует сеть для загрузки тайлов, стилей, изображений спрайтов и шрифтов, и все эти запросы могут быть перехвачены и изменены на уровне конфигурации.

Основной механизм управления URL-запросами реализуется через опцию transformRequest при инициализации карты. Эта функция позволяет перехватывать каждый сетевой запрос перед его отправкой и изменять параметры запроса, включая URL, заголовки и режимы кеширования.

Базовая структура:

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v12',
  accessToken: 'TOKEN',
  transformRequest: (url, resourceType) => {
    return {
      url,
      headers: {
        'X-Custom-Header': 'value'
      }
    };
  }
});

Функция принимает:

  • url — исходный адрес ресурса
  • resourceType — тип ресурса (tile, glyphs, sprite, image, source и др.)

Возвращаемый объект может содержать:

  • изменённый url
  • headers
  • credentials
  • referrerPolicy

Это позволяет централизованно управлять всеми сетевыми запросами карты.

Ограничение и фильтрация доменов источников

Одним из ключевых сценариев является ограничение допустимых доменов, с которых могут загружаться ресурсы. Это используется для предотвращения подключения сторонних tile-серверов или подмены источников данных.

Пример фильтрации:

const ALLOWED_DOMAINS = [
  'api.mapbox.com',
  'tiles.mycompany.com'
];

const map = new mapboxgl.Map({
  container: 'map',
  style: 'style.json',
  transformRequest: (url) => {
    const isAllowed = ALLOWED_DOMAINS.some(domain => url.includes(domain));

    if (!isAllowed) {
      return { url: '' };
    }

    return { url };
  }
});

В реальных системах вместо блокировки чаще используется перенаправление на прокси-сервер.

Перенаправление URL и проксирование запросов

Часто применяется схема, при которой все запросы к внешним ресурсам перенаправляются через собственный backend. Это позволяет:

  • скрыть access token
  • контролировать нагрузку
  • логировать обращения
  • кэшировать ответы

Пример замены URL:

transformRequest: (url, resourceType) => {
  if (url.startsWith('https://api.mapbox.com')) {
    return {
      url: `/proxy?url=${encodeURIComponent(url)}`
    };
  }

  return { url };
}

Такой подход особенно важен при работе в корпоративных средах.

Контроль доступа через access token и доменные ограничения

Mapbox access token может быть ограничен по доменам на стороне панели управления. Однако дополнительная защита реализуется на клиенте через контроль URL.

Типичные источники, зависящие от токена:

  • mapbox://styles/...
  • mapbox://tilesets/...
  • mapbox://sprites/...
  • mapbox://fonts/...

При рендеринге эти схемы автоматически преобразуются в HTTPS-запросы к API Mapbox. Управление ими возможно через transformRequest.

Пример модификации заголовков:

transformRequest: (url) => {
  if (url.includes('api.mapbox.com')) {
    return {
      url,
      headers: {
        Authorization: 'Bearer TOKEN'
      }
    };
  }
  return { url };
}

Типы ресурсов и их URL-структура

Mapbox GL JS использует несколько категорий сетевых ресурсов, каждая из которых имеет собственный URL-паттерн:

Тайлы (tiles)

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

https://api.mapbox.com/v4/{tileset}/{z}/{x}/{y}.vector.pbf

Стили (styles)

JSON-описание карты:

mapbox://styles/{user}/{style_id}

или

https://api.mapbox.com/styles/v1/{user}/{style_id}

Спрайты (sprites)

https://api.mapbox.com/styles/v1/{user}/{style_id}/sprite.png

Шрифты (glyphs)

https://api.mapbox.com/fonts/v1/{user}/{fontstack}/{range}.pbf

Каждый из этих URL может быть перехвачен и переписан через transformRequest, что позволяет полностью контролировать источники визуальных данных.

Ограничение кастомных источников данных

При добавлении собственных источников через addSource также можно контролировать URL:

map.addSource('custom-tiles', {
  type: 'vector',
  tiles: [
    'https://tiles.myserver.com/data/{z}/{x}/{y}.pbf'
  ]
});

С точки зрения безопасности важно проверять такие URL на уровне transformRequest, иначе возможно подключение внешних источников без контроля.

Content Security Policy и ограничения загрузки ресурсов

Mapbox GL JS тесно взаимодействует с CSP (Content Security Policy). При строгой политике безопасности необходимо явно разрешать домены:

Content-Security-Policy: 
  connect-src 'self' https://api.mapbox.com https://tiles.mycompany.com;
  img-src 'self' dat a: https:;
  worker-src 'self' blob:;

Особое внимание требуется для:

  • worker-src — используется для векторных тайлов
  • connect-src — все API-запросы
  • img-src — спрайты и изображения

При неправильной настройке CSP карта может частично или полностью перестать загружаться.

Перехват запросов и работа с worker-средой

Mapbox GL JS использует Web Workers для обработки векторных тайлов. Это означает, что часть URL-запросов выполняется вне основного потока.

Ограничения:

  • не все заголовки могут быть изменены одинаково в main thread и worker
  • некоторые запросы обходят fetch-обёртки браузера напрямую через внутренний слой библиотеки

Поэтому transformRequest остаётся основным универсальным механизмом контроля.

Кеширование и контроль повторных запросов

URL-ограничения часто дополняются стратегией кеширования. Поскольку один и тот же ресурс может запрашиваться многократно, важно учитывать стабильность URL.

Пример стабилизации запросов:

transformRequest: (url) => {
  const normalizedUrl = new URL(url);
  normalizedUrl.searchParams.set('cache_bust', '0');

  return {
    url: normalizedUrl.toString()
  };
}

Это позволяет управлять кешированием через прокси или CDN.

Защита от подмены ресурсов

В продакшн-архитектурах часто требуется защита от:

  • подмены tileset URL через динамический стиль
  • внедрения сторонних sprite/glyph endpoints
  • загрузки несанкционированных raster tiles

Типовой подход заключается в жёстком whitelist на уровне transformRequest:

const ALLOWED_PREFIXES = [
  'https://api.mapbox.com',
  'https://tiles.mycompany.com'
];

transformRequest: (url) => {
  const allowed = ALLOWED_PREFIXES.some(prefix => url.startsWith(prefix));

  if (!allowed) {
    throw new Error('Blocked resource: ' + url);
  }

  return { url };
}

Работа с приватными и подписанными URL

В некоторых архитектурах используются временные подписанные URL (signed URLs). В этом случае transformRequest может добавлять токены доступа:

transformRequest: (url) => {
  if (url.includes('tiles.mycompany.com')) {
    const signedUrl = `${url}?signature=ABC123`;
    return { url: signedUrl };
  }
  return { url };
}

Такой подход часто применяется совместно с серверной генерацией подписи.

Ограничение типов ресурсов через resourceType

Параметр resourceType позволяет разделять логику обработки URL:

transformRequest: (url, resourceType) => {
  if (resourceType === 'Tile') {
    return { url: `/tile-proxy?u=${encodeURIComponent(url)}` };
  }

  if (resourceType === 'Glyphs') {
    return { url: `/font-proxy?u=${encodeURIComponent(url)}` };
  }

  return { url };
}

Это даёт возможность строить отдельные политики безопасности для разных типов данных карты.