Compartir a través de


Inicio rápido: Compilación de una aplicación web con Microsoft Planetary Computer Pro

En este inicio rápido, creará una aplicación web que muestra imágenes satélite y datos geoespaciales de GeoCatalog en un mapa interactivo. Los usuarios se autentican con el identificador de Entra de Microsoft, consultan colecciones de STAC y representan iconos de mapa, todos ellos desde javaScript del explorador.

Lo que aprende:

  • Autenticación de usuarios y adquisición de tokens de acceso mediante MSAL.js
  • Consulta de la API de STAC para detectar colecciones y elementos
  • Mostrar iconos ráster en un mapa mapLibre GL con encabezados de autorización
  • Creación de capas de mosaico sin problemas en colecciones completas
  • Descargar recursos sin procesar mediante tokens de SAS

Los patrones de código funcionan con cualquier marco de JavaScript moderno (React, Vue, Angular) o JavaScript puro. Las API de GeoCatalog tienen compatibilidad completa con CORS, por lo que puede llamarlas directamente desde localhost durante el desarrollo, no es necesario ningún proxy.

Puede descargar y probar este código desde el repositorio público de GitHub microsoft Planetary Computer Pro.

Prerrequisitos

Introducción a la arquitectura

Una aplicación web típica de GeoCatalog sigue esta arquitectura:

Diagrama que muestra la arquitectura de una aplicación web GeoCatalog con un cliente del explorador que se conecta a Microsoft Entra ID para la autenticación y a las API de GeoCatalog para el acceso a datos.

Registro de la aplicación en el identificador de Microsoft Entra

Antes de que la aplicación web pueda autenticar a los usuarios, regístrelo en el identificador de Microsoft Entra. En este inicio rápido se usa un registro de aplicación de página única (SPA), que es ideal para aplicaciones JavaScript del lado cliente y el desarrollo local. Los patrones de integración de API que se muestran en pasos posteriores funcionan con cualquier tipo de aplicación.

Nota:

En el caso de las aplicaciones de producción con un servidor back-end, considere la posibilidad de elegir un tipo de registro diferente (Web, Nativo, etc.). Consulte Configuración de la autenticación de aplicaciones para obtener instrucciones sobre cómo elegir el enfoque adecuado para su escenario.

Registro como una aplicación de página única

  1. Vaya a Microsoft Entra ID en Azure Portal.
  2. Seleccione Registros de aplicaciones en el panel lateral.
  3. Seleccione Nuevo registro.
  4. Escriba un nombre para la aplicación (por ejemplo, "GeoCatalog Web App").
  5. En Tipos de cuenta admitidos, seleccione Solo cuentas en este directorio organizativo.
  6. En URI de redirección, seleccione Aplicación de página única (SPA) y escriba la dirección URL de desarrollo (por ejemplo, http://localhost:5173).
  7. Seleccione Registrar.

Después del registro, tenga en cuenta los valores siguientes de la página Información general :

  • Id. de la aplicación (cliente)
  • Id. de directorio (inquilino)

Para más información, revise el inicio rápido de registro de aplicaciones.

Concesión de permisos de API

La aplicación necesita permiso para llamar a geocatalog API en nombre de los usuarios que han iniciado sesión:

  1. En el registro de la aplicación, seleccione Permisos> de APIAgregar un permiso.
  2. Seleccione LAS API que usa mi organización y busque Azure Orbital Spatio.
  3. Seleccione Permisos delegados y compruebe user_impersonation.
  4. Seleccione Agregar permisos.
  5. Si es administrador, seleccione Conceder consentimiento de administrador en nombre de todos los usuarios de su arrendatario.

Configuración de la aplicación

La aplicación necesita los siguientes valores de configuración. La forma de proporcionar estos valores depende de las herramientas de compilación (variables de entorno, archivos de configuración, etc.):

Configuración Importancia Description
Dirección URL del catálogo https://{name}.{region}.geocatalog.spatio.azure.com El punto de conexión de GeoCatalog
Id. de inquilino Desde el registro de aplicaciones Su inquilino de Microsoft Entra
Id. de cliente Desde el registro de aplicaciones Identificador de cliente de la aplicación
Ámbito de API https://geocatalog.spatio.azure.com/.default Use siempre este valor exacto.

Instalación de dependencias

Instale la Biblioteca de autenticación de Microsoft (MSAL) para las aplicaciones del explorador y una biblioteca de mapas:

npm install @azure/msal-browser maplibre-gl
  • @azure/msal-browser : controla la autenticación de OAuth 2.0 con el identificador de Entra de Microsoft
  • maplibre-gl : biblioteca de mapas de código abierto para la visualización de iconos

Sugerencia

Estructura del proyecto: Los ejemplos de código de este inicio rápido son funciones independientes que puede organizar como prefiera. Un patrón común:

  • auth.js: configuración de MSAL y funciones de token
  • api.js: API de STAC, API de Tiler y funciones de token de SAS
  • map.js: Inicialización de MapLibre y administración de capas de mosaicos
  • App.js o main.js: conectar todo con la UI.

Cada función recibe sus dependencias (tokens de acceso, direcciones URL) como parámetros, lo que facilita la integración en cualquier marco o estructura de proyecto.

Implementación de la autenticación MSAL

Captura de pantalla que muestra el flujo de autenticación en una aplicación web de ejemplo.

Configure MSAL para la autenticación del explorador. En el ejemplo siguiente se muestra el patrón de configuración de claves y adquisición de tokens:

import { PublicClientApplication, InteractionRequiredAuthError } from '@azure/msal-browser';

// Configuration - replace with your values or load from environment/config
const msalConfig = {
  auth: {
    clientId: 'YOUR_CLIENT_ID',
    authority: 'https://login.microsoftonline.com/YOUR_TENANT_ID',
    redirectUri: window.location.origin,
  },
  cache: {
    cacheLocation: 'sessionStorage',
    storeAuthStateInCookie: false,
  },
};

// Create MSAL instance
const msalInstance = new PublicClientApplication(msalConfig);

// GeoCatalog API scope - always use this exact value
const scopes = ['https://geocatalog.spatio.azure.com/.default'];

/**
 * Acquire an access token for GeoCatalog API calls.
 * Tries silent acquisition first, falls back to popup if needed.
 */
async function getAccessToken() {
  const account = msalInstance.getActiveAccount() || msalInstance.getAllAccounts()[0];
  
  if (!account) {
    throw new Error('No authenticated account. Call login() first.');
  }

  try {
    // Try silent token acquisition (uses cached token)
    const result = await msalInstance.acquireTokenSilent({ account, scopes });
    return result.accessToken;
  } catch (error) {
    // If silent fails (token expired), fall back to popup
    if (error instanceof InteractionRequiredAuthError) {
      const result = await msalInstance.acquireTokenPopup({ scopes });
      return result.accessToken;
    }
    throw error;
  }
}

/**
 * Sign in the user via popup.
 */
async function login() {
  const result = await msalInstance.loginPopup({ scopes });
  msalInstance.setActiveAccount(result.account);
  return result.account;
}

/**
 * Sign out the user.
 */
function logout() {
  msalInstance.logoutPopup();
}

API de STAC: Consulta de colecciones y elementos

La API de STAC de GeoCatalog proporciona puntos de conexión para detectar y consultar datos geoespaciales. Todas las solicitudes requieren un encabezado Authorization con un token Bearer obtenido de Implementación de autenticación MSAL.

Enumerar colecciones

Captura de pantalla que muestra la lista de colecciones de STAC en una aplicación web de ejemplo.

const API_VERSION = '2025-04-30-preview';

async function listCollections(accessToken, catalogUrl) {
  const url = `${catalogUrl}/stac/collections?api-version=${API_VERSION}`;
  
  const response = await fetch(url, {
    headers: {
      'Authorization': `Bearer ${accessToken}`,
    },
  });
  
  if (!response.ok) {
    throw new Error(`Failed to list collections: ${response.statusText}`);
  }
  
  const data = await response.json();
  return data.collections; // Array of STAC Collection objects
}

Enumerar elementos de una colección

Captura de pantalla que muestra la lista de elementos de STAC en una aplicación web de ejemplo.

const API_VERSION = '2025-04-30-preview';

async function listItems(accessToken, catalogUrl, collectionId, limit = 10) {
  const url = `${catalogUrl}/stac/collections/${collectionId}/items?limit=${limit}&api-version=${API_VERSION}`;
  
  const response = await fetch(url, {
    headers: {
      'Authorization': `Bearer ${accessToken}`,
    },
  });
  
  if (!response.ok) {
    throw new Error(`Failed to list items: ${response.statusText}`);
  }
  
  const data = await response.json();
  return data.features; // Array of STAC Item objects
}

Búsqueda entre colecciones

Captura de pantalla que muestra cómo usar la búsqueda de STAC para devolver elementos de interés.

const API_VERSION = '2025-04-30-preview';

async function searchItems(accessToken, catalogUrl, searchParams) {
  const url = `${catalogUrl}/stac/search?api-version=${API_VERSION}`;
  
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(searchParams),
  });
  
  if (!response.ok) {
    throw new Error(`Search failed: ${response.statusText}`);
  }
  
  return await response.json();
}

// Example usage:
const results = await searchItems(token, catalogUrl, {
  collections: ['my-collection'],
  bbox: [-122.5, 37.5, -122.0, 38.0],  // [west, south, east, north]
  datetime: '2024-01-01/2024-12-31',
  limit: 20,
});

Direcciones URL de icono: crear direcciones URL para la visualización de mapas

GeoCatalog Tiler API sirve datos ráster como iconos de mapa. Construya direcciones URL de icono con el siguiente patrón:

Baldosas de un solo elemento

Captura de pantalla que muestra cómo mostrar iconos para un solo elemento.

{catalogUrl}/data/collections/{collectionId}/items/{itemId}/tiles/{z}/{x}/{y}@1x.png
  ?api-version=2025-04-30-preview
  &tileMatrixSetId=WebMercatorQuad
  &assets=visual

Función del generador de URL de mosaico

const API_VERSION = '2025-04-30-preview';

/**
 * Build a tile URL template for a STAC item.
 * Returns a URL with {z}/{x}/{y} placeholders for use with map libraries.
 */
function buildTileUrl(catalogUrl, collectionId, itemId, options = {}) {
  const { assets = 'visual', colormap, rescale } = options;
  
  const base = `${catalogUrl}/data/collections/${collectionId}/items/${itemId}/tiles/{z}/{x}/{y}@1x.png`;
  
  const params = new URLSearchParams();
  params.set('api-version', API_VERSION);
  params.set('tileMatrixSetId', 'WebMercatorQuad');
  params.set('assets', assets);
  
  if (colormap) params.set('colormap_name', colormap);
  if (rescale) params.set('rescale', rescale);
  
  return `${base}?${params.toString()}`;
}

// Example usage:
const tileUrl = buildTileUrl(
  'https://mygeocatalog.northcentralus.geocatalog.spatio.azure.com',
  'aerial-imagery',
  'image-001',
  { assets: 'visual' }
);

Parámetros del mosaico clave

Parámetro Obligatorio Description
api-version Versión de API (2025-04-30-preview)
tileMatrixSetId Uso WebMercatorQuad para mapas web
assets Nombres de recursos que se van a representar (por ejemplo: visual, image)
colormap_name No Mapa de colores con nombre (ejemplo: viridis, terrain)
rescale No Intervalo de valores para el escalado (ejemplo: 0,255)
asset_bidx No Índices de banda (por ejemplo: image\|1,2,3 para RGB)

Nota:

Para colecciones con imágenes de cuatro bandas (como NAIP con RGB + NIR), use asset_bidx=image|1,2,3 para seleccionar solo las bandas RGB. El generador de mosaicos no puede codificar cuatro bandas como PNG.


Integración de mapas: mostrar iconos con MapLibre GL

Las bibliotecas de mapas como MapLibre GL, Leaflet y OpenLayers pueden mostrar iconos de trama. El desafío clave es agregar encabezados de autorización a solicitudes de icono, ya que estas bibliotecas capturan iconos directamente.

Ejemplo de MapLibre GL

MapLibre GL proporciona una transformRequest opción para insertar encabezados:

import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';

// Store the current access token
let currentAccessToken = null;

function initializeMap(containerId, accessToken) {
  currentAccessToken = accessToken;
  
  const map = new maplibregl.Map({
    container: containerId,
    style: {
      version: 8,
      sources: {
        osm: {
          type: 'raster',
          tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
          tileSize: 256,
          attribution: '© OpenStreetMap contributors',
        },
      },
      layers: [{ id: 'osm', type: 'raster', source: 'osm' }],
    },
    center: [0, 0],
    zoom: 2,
    // Add authorization header to tile requests
    transformRequest: (url, resourceType) => {
      // Only add auth for GeoCatalog tile requests
      if (url.includes('geocatalog.spatio.azure.com') && currentAccessToken) {
        return {
          url,
          headers: { 'Authorization': `Bearer ${currentAccessToken}` },
        };
      }
      return { url };
    },
  });
  
  return map;
}

function addTileLayer(map, tileUrl, bounds) {
  // Remove existing layer and source if present
  if (map.getLayer('data-layer')) {
    map.removeLayer('data-layer');
  }
  if (map.getSource('data-tiles')) {
    map.removeSource('data-tiles');
  }
  
  // Add tile source
  map.addSource('data-tiles', {
    type: 'raster',
    tiles: [tileUrl],
    tileSize: 256,
    minzoom: 10,  // Many aerial collections require zoom 10+
    maxzoom: 18,
  });
  
  // Add tile layer
  map.addLayer({
    id: 'data-layer',
    type: 'raster',
    source: 'data-tiles',
  });
  
  // Zoom to bounds [west, south, east, north]
  if (bounds) {
    map.fitBounds([[bounds[0], bounds[1]], [bounds[2], bounds[3]]], { padding: 50 });
  }
}

Importante

Se llama a la función transformRequest para cada solicitud de icono. Almacene el token de acceso en una variable a la que transformRequest pueda acceder y actualícelo cuando se actualice el token.


Azulejos de mosaico: Mostrar imágenes de toda la colección

Captura de pantalla que muestra cómo mostrar iconos de mosaico para una colección.

Para ver todos los elementos de una colección como una capa continua, registre una búsqueda de mosaico y use el identificador de búsqueda devuelto.

const API_VERSION = '2025-04-30-preview';

/**
 * Register a mosaic search for a collection.
 * Returns a search ID that can be used to fetch mosaic tiles.
 */
async function registerMosaic(catalogUrl, collectionId, accessToken) {
  const url = `${catalogUrl}/data/mosaic/register?api-version=${API_VERSION}`;
  
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      collections: [collectionId],
    }),
  });
  
  if (!response.ok) {
    throw new Error(`Failed to register mosaic: ${response.statusText}`);
  }
  
  const data = await response.json();
  // Note: API returns 'searchid' (lowercase), not 'searchId'
  return data.searchid;
}

/**
 * Build a mosaic tile URL template.
 */
function buildMosaicTileUrl(catalogUrl, searchId, collectionId, options = {}) {
  const { assets = 'visual' } = options;
  
  const base = `${catalogUrl}/data/mosaic/${searchId}/tiles/{z}/{x}/{y}@1x.png`;
  
  const params = new URLSearchParams();
  params.set('api-version', API_VERSION);
  params.set('tileMatrixSetId', 'WebMercatorQuad');
  params.set('collection', collectionId);
  params.set('assets', assets);
  
  return `${base}?${params.toString()}`;
}

Tokens de SAS: descarga de activos sin procesar

La API de SAS proporciona tokens de tiempo limitado para descargar archivos de recursos sin procesar (GeoTIFFs, COG y otros archivos) directamente desde Azure Blob Storage. Use esta opción cuando necesite los archivos de origen originales en lugar de los iconos representados.

Importante

Los tokens de SAS solo permiten descargas en aplicaciones del explorador. Debido a las directivas de CORS de Azure Blob Storage, los exploradores no pueden leer datos de blobs a través de JavaScript fetch(). Consulte la sección Limitaciones del explorador .

Captura de pantalla que muestra cómo descargar recursos mediante un token de SAS.

Obtención de un token de SAS

const API_VERSION = '2025-04-30-preview';

/**
 * Get a SAS token for accessing assets in a collection.
 * Returns a token string that can be appended to asset URLs.
 */
async function getCollectionSasToken(accessToken, catalogUrl, collectionId) {
  const url = `${catalogUrl}/sas/token/${collectionId}?api-version=${API_VERSION}`;
  
  const response = await fetch(url, {
    headers: {
      'Authorization': `Bearer ${accessToken}`,
    },
  });
  
  if (!response.ok) {
    throw new Error(`Failed to get SAS token: ${response.statusText}`);
  }
  
  const data = await response.json();
  return data.token; // SAS token string
}

Compilación de una dirección URL de descarga firmada

/**
 * Build a signed URL for downloading an asset.
 * Appends the SAS token to the asset's href.
 */
function buildSignedAssetUrl(assetHref, sasToken) {
  const separator = assetHref.includes('?') ? '&' : '?';
  return `${assetHref}${separator}${sasToken}`;
}

// Example usage:
const sasToken = await getCollectionSasToken(accessToken, catalogUrl, 'my-collection');
const assetHref = item.assets['visual'].href;
const signedUrl = buildSignedAssetUrl(assetHref, sasToken);

Desencadenar una descarga de archivos

/**
 * Trigger a browser download for an asset file.
 * Works by creating a temporary anchor element.
 */
function downloadAsset(signedUrl, filename) {
  const link = document.createElement('a');
  link.href = signedUrl;
  link.download = filename || 'download';
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
}

// Example: Download an asset
downloadAsset(signedUrl, 'aerial-image.tif');

Limitaciones del explorador

Los tokens de SAS funcionan de forma diferente en exploradores frente al código del lado servidor:

Caso de uso Navegador Server-side
Descargar archivos (el usuario selecciona el vínculo) ✅ Funciona ✅ Funciona
Lectura de datos de blobs a través de fetch() ❌ CORS bloqueado ✅ Funciona
Procesamiento de píxeles sin procesar en JavaScript ❌ No es posible ✅ Funciona

Las descargas del explorador funcionan porque la navegación (haciendo clic en vínculos) omite CORS. Sin embargo, fetch() las solicitudes a Azure Blob Storage se bloquean porque la cuenta de almacenamiento no incluye el origen de la aplicación en su directiva de CORS.

Si la aplicación necesita leer y procesar datos de recursos sin procesar en el explorador, implemente un proxy del lado servidor:

Nota:

El código siguiente es un ejemplo simplificado para ilustrar el patrón de proxy. En el caso de las aplicaciones de producción, el punto de conexión de proxy debe autenticar las solicitudes (por ejemplo, reenviando el token de portador del usuario o mediante la autenticación de sesión) y validar que el usuario está autorizado para acceder a los recursos solicitados.

// ❌ Browser: This fails due to CORS
const response = await fetch(signedUrl);
const data = await response.arrayBuffer(); // Error!

// ✅ Browser: Call your backend instead
const response = await fetch('/api/proxy-asset', {
  method: 'POST',
  body: JSON.stringify({ collectionId, itemId, assetName })
});
const data = await response.json(); // Works!

El back-end puede capturar el blob mediante el token de SAS y devolver los resultados procesados.


Consideraciones de desarrollo

Soporte técnico de CORS

Las API de GeoCatalog incluyen compatibilidad completa con CORS con Access-Control-Allow-Origin: *. Las aplicaciones basadas en explorador pueden realizar solicitudes directas a GeoCatalog desde cualquier origen, incluido http://localhost durante el desarrollo. No se requiere ningún proxy ni solución alternativa.

La API permite el Authorization encabezado en las solicitudes CORS, por lo que las llamadas autenticadas fetch() funcionan directamente desde javaScript del explorador.

Elección del método de acceso a datos correcto

Método Navegador fetch() Descargas del explorador Server-side Mejor para
Tiler API ✅ Totalmente compatible ✅ Sí ✅ Sí Visualización de mapa
SAS Tokens ❌ CORS bloqueado ✅ Sí ✅ Sí Descargas de archivos RAW
  • API de tiler: se usa para mostrar imágenes en mapas. Devuelve iconos PNG o WebP representados con compatibilidad completa con CORS. Consulte Direcciones URL de icono e Integración de mapas.

  • Tokens de SAS: usar para descargar archivos de origen originales (GeoTIFFs, COGs). Las descargas del explorador funcionan, pero fetch() las directivas de CORS de Azure Blob Storage las bloquean. Consulte Tokens de SAS para obtener más información y soluciones alternativas.

Actualización de tokens

Los tokens de acceso expiran, normalmente después de una hora. La aplicación debe:

  1. Controle los errores 401 mediante la adquisición de un nuevo token.
  2. Use la adquisición silenciosa de tokens de MSAL, que actualiza automáticamente los tokens expirados.
  3. Actualice el token de referencia usado por el transformRequest del mapa.

Control de errores

Control de escenarios de error comunes:

Estado HTTP Causa Solución
401 Token expirado o no válido Actualización del token de acceso
404 Elemento o colección no encontrado Verificar que existen identificadores
424 Extensión de datos fuera del icono Esperado: manejar con suavidad

Solución de problemas

Error Causa Solución
"AADSTS50011: no coinciden las direcciones URL de respuesta" El URI de redirección en el código no coincide con el registro en Microsoft Entra ID Agregue la dirección URL de desarrollo (por ejemplo, http://localhost:3000) como un URI de redirección de SPA en el registro de la aplicación
Error "Ámbito no válido" Uso de la dirección URL de GeoCatalog en lugar del ámbito de la API Use https://geocatalog.spatio.azure.com/.default como ámbito
401 No autorizado en solicitudes de icono Biblioteca de mapas que no incluye encabezados de autenticación Use transformRequest (MapLibre) para agregar el token de portador; asegúrese de que el token está activo.
Los iconos no se alinean con el mapa base Conjunto de matriz de iconos incorrecto Utilice tileMatrixSetId=WebMercatorQuad para la proyección Web Mercator (EPSG:3857)
"No se pudo descodificar la imagen" Nombre de recurso incorrecto, imágenes de varias bandas o extensión de datos externa Compruebe que los nombres de item_assets son válidos; use asset_bidx=image\|1,2,3 para RGB; se espera una cobertura externa de 404/424

Pasos siguientes