CORS настройка

В веб-картографии и 3D-геовизуализации библиотека CesiumJS активно взаимодействует с внешними источниками данных: тайлы, изображения, 3D Tiles, terrain, модели glTF, GeoJSON и потоковые сервисы. Почти все эти ресурсы загружаются через HTTP(S) и подчиняются политике безопасности браузера Same-Origin Policy.

Cross-Origin Resource Sharing (CORS) определяет, может ли браузер разрешить JavaScript-коду получать доступ к ресурсам с другого домена. При отсутствии корректных CORS-заголовков загрузка данных в CesiumJS приводит к блокировкам, даже если URL корректен и сервер отвечает.


Механизм CORS и влияние на CesiumJS

Браузер разделяет происхождение запроса по трём компонентам:

  • схема (http / https)
  • домен
  • порт

Запрос считается cross-origin, если хотя бы один компонент отличается.

При загрузке ресурсов в CesiumJS типичный поток выглядит так:

  • запрос terrain tiles с удалённого сервера
  • запрос imagery provider (XYZ, WMTS, TMS)
  • запрос 3D Tileset JSON и бинарных .b3dm / .pnts файлов
  • загрузка glTF моделей

Если сервер не возвращает заголовок:

Access-Control-Allow-Origin: *

или соответствующий origin, браузер блокирует ответ, даже если сетевой запрос успешен.


Типичные ошибки при отсутствии CORS

В консоли браузера возникают сообщения:

  • No 'Access-Control-Allow-Origin' header is present
  • CORS policy blocked the request
  • Response to preflight request doesn't pass access control check

В CesiumJS это часто проявляется как:

  • пустая сцена (terrain не загружается)
  • отсутствие тайлов изображения
  • исчезновение 3D Tileset после частичной загрузки
  • ошибки в Cesium.js при декодировании ресурсов

Настройка CORS на сервере

Nginx

Наиболее распространённая конфигурация:

location / {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods "GET, OPTIONS";
    add_header Access-Control-Allow-Headers "Origin, Authorization, Accept";
}

Для более строгой политики:

add_header Access-Control-Allow-Origin "https://example.com";

Важно учитывать preflight-запросы OPTIONS:

if ($request_method = OPTIONS) {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
    add_header Access-Control-Allow-Headers "Content-Type, Authorization";
    return 204;
}

Apache

В .htaccess или конфигурации виртуального хоста:

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, OPTIONS"
Header set Access-Control-Allow-Headers "Origin, Content-Type, Accept"

Node.js (Express)

Для API и статических ресурсов:

import express from "express";
import cors from "cors";

const app = express();

app.use(cors({
  origin: "*",
  methods: ["GET", "POST", "OPTIONS"],
  allowedHeaders: ["Content-Type", "Authorization"]
}));

CORS и Cesium ion

При использовании облачного сервиса данных Cesium ion доступ к ассетам происходит через signed URLs.

Особенности:

  • CORS уже настроен на стороне сервиса
  • запросы используют временные токены
  • доступ ограничен по времени и ключу

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

import { Ion } from "cesium";

Ion.defaultAccessToken = "YOUR_TOKEN";

Проблемы CORS в этом случае обычно связаны не с сервером ion, а с промежуточными прокси или корпоративными фильтрами.


Локальная разработка и CORS

При запуске CesiumJS локально часто возникает конфликт из-за file:// протокола.

Запрещённые сценарии:

  • открытие HTML напрямую из файловой системы
  • загрузка локальных ресурсов без HTTP сервера

Корректные варианты:

Python сервер

python -m http.server 8080

Node static server

npx serve .

Vite

export default {
  server: {
    cors: true
  }
}

CORS для 3D Tiles

3D Tiles используют множественные уровни запросов:

  • tileset.json
  • .b3dm / .i3dm / .pnts
  • текстуры
  • внешние ресурсы glTF

Каждый из этих запросов требует CORS.

Особенно критично:

  • бинарные тайлы (без CORS они полностью блокируются)
  • текстуры внутри glTF (отдельные HTTP-запросы)
  • metadata JSON

Preflight-запросы и их влияние

Preflight возникает при:

  • нестандартных заголовках
  • авторизации (Authorization header)
  • POST запросах

CesiumJS может инициировать preflight при использовании:

  • кастомных Request объектов
  • защищённых API
  • проксируемых источников

Пример:

viewer.imageryLayers.addImageryProvider(
  new Cesium.UrlTemplateImageryProvider({
    url: "https://tiles.example.com/{z}/{x}/{y}.png",
    headers: {
      Authorization: "Bearer token"
    }
  })
);

Такой запрос почти всегда вызывает OPTIONS preflight.


Proxy как обход CORS

Когда сервер не поддерживает CORS, используется проксирование.

Простой Node proxy

import express from "express";
import fetch from "node-fetch";

const app = express();

app.get("/proxy", async (req, res) => {
  const url = req.query.url;

  const response = await fetch(url);
  const data = await response.arrayBuffer();

  res.set("Access-Control-Allow-Origin", "*");
  res.send(Buffer.from(data));
});

CesiumJS:

url: "http://localhost:3000/proxy?url=https://example.com/tiles/{z}/{x}/{y}.png"

S3 и CORS

При использовании AWS S3 необходимо явно включить CORS-конфигурацию бакета:

[
  {
    "AllowedOrigins": ["*"],
    "AllowedMethods": ["GET"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": []
  }
]

Без этого CesiumJS не сможет загрузить:

  • terrain
  • imagery
  • tilesets

GitHub Pages и ограничения

GitHub Pages по умолчанию поддерживает CORS для статических файлов, но проблемы возникают при:

  • загрузке ресурсов с другого домена
  • использовании API без CORS
  • смешанном HTTP/HTTPS

Особенность:

  • HTTPS обязателен
  • смешанный контент блокируется полностью

Debugging CORS в CesiumJS

Основные методы диагностики:

Network tab

Проверка:

  • статус ответа (200 / 403 / (blocked))
  • наличие заголовков CORS
  • OPTIONS запросы

Cesium log

viewer.scene.globe.tileLoadProgressEvent.addEventListener(function (queueLength) {
  console.log(queueLength);
});

Включение подробных ошибок

Cesium.Cesium3DTileset.debugShowBoundingVolume = true;

Частые архитектурные ошибки

  • хранение tileset на другом домене без CORS
  • попытка загрузки локальных файлов без HTTP
  • отсутствие обработки OPTIONS запросов
  • использование wildcard * вместе с credentials
  • смешение HTTP и HTTPS ресурсов

Безопасные стратегии настройки

  • явное указание origin вместо * при авторизации
  • использование CDN с поддержкой CORS
  • единый домен для tileset и приложения
  • проксирование только при невозможности изменить сервер
  • разделение публичных и приватных ресурсов

CORS и производительность загрузки

Неправильная конфигурация CORS не только блокирует загрузку, но и влияет на:

  • параллелизм запросов
  • кеширование браузера
  • поведение HTTP/2 соединений
  • retry механизмы CesiumJS

При корректной настройке:

  • тайлы загружаются параллельно
  • уменьшается latency первого рендера
  • стабилизируется прогрузка terrain

Особенности работы с кастомными провайдерами

При создании собственного ImageryProvider или TerrainProvider:

  • каждый fetch должен учитывать CORS
  • нельзя обходить браузерные ограничения напрямую
  • все запросы проходят через fetch или XHR

Пример:

class CustomProvider extends Cesium.ImageryProvider {
  requestImage(x, y, level) {
    return Cesium.Resource.fetchImage({
      url: this.urlTemplate
        .replace("{x}", x)
        .replace("{y}", y)
        .replace("{z}", level)
    });
  }
}

Итоговая модель взаимодействия

  • CesiumJS формирует HTTP-запросы к данным сцены
  • браузер применяет Same-Origin Policy
  • сервер обязан явно разрешать cross-origin доступ
  • любые несоответствия приводят к блокировке ресурсов
  • архитектура приложения должна учитывать CORS на уровне источников данных, а не клиента