Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
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
- Una cuenta de Azure con una suscripción activa. Cree una cuenta gratuita.
- Un recurso GeoCatalog implementado con al menos una colección que contiene elementos.
- La identidad de usuario debe tener acceso de Lector de GeoCatalog (o superior) al recurso de GeoCatalog. Consulte Administración del acceso a un recurso de GeoCatalog.
- Node.js versión 18 o posterior.
Introducción a la arquitectura
Una aplicación web típica de GeoCatalog sigue esta arquitectura:
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
- Vaya a Microsoft Entra ID en Azure Portal.
- Seleccione Registros de aplicaciones en el panel lateral.
- Seleccione Nuevo registro.
- Escriba un nombre para la aplicación (por ejemplo, "GeoCatalog Web App").
- En Tipos de cuenta admitidos, seleccione Solo cuentas en este directorio organizativo.
- 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). - 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:
- En el registro de la aplicación, seleccione Permisos> de APIAgregar un permiso.
- Seleccione LAS API que usa mi organización y busque Azure Orbital Spatio.
- Seleccione Permisos delegados y compruebe user_impersonation.
- Seleccione Agregar permisos.
- 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.jsomain.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
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
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
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
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
{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 |
Sí | Versión de API (2025-04-30-preview) |
tileMatrixSetId |
Sí | Uso WebMercatorQuad para mapas web |
assets |
Sí | 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
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 .
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:
- Controle los errores 401 mediante la adquisición de un nuevo token.
- Use la adquisición silenciosa de tokens de MSAL, que actualiza automáticamente los tokens expirados.
- Actualice el token de referencia usado por el
transformRequestdel 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 |