Snabbstart: Skapa ett webbprogram med Microsoft Planetary Computer Pro

I den här snabbstarten skapar du ett webbprogram som visar satellitbilder och geospatiala data från din GeoCatalog på en interaktiv karta. Du autentiserar användare med Microsoft Entra-ID, förfrågar STAC-samlingar och renderar kartplattor – allt från webbläsaren JavaScript.

Det här lär du dig:

  • Autentisera användare och hämta åtkomsttoken med hjälp av MSAL.js
  • Anropa STAC-API för att upptäcka samlingar och föremål
  • Visa rasterpaneler på en MapLibre GL-karta med auktoriseringshuvuden
  • Skapa sömlösa mosaikskikt i hela samlingar
  • Ladda ned råtillgångar med hjälp av SAS-token

Kodmönstren fungerar med alla moderna JavaScript-ramverk (React, Vue, Angular) eller vanilj-JavaScript. GeoCatalog-API:er har fullständigt CORS-stöd, så du kan anropa dem direkt från localhost under utvecklingen – ingen proxy krävs.

Du kan ladda ned och testa den här koden från den offentliga GitHub-lagringsplatsen Microsoft Planetary Computer Pro.

Förutsättningar

Översikt över arkitektur

Ett typiskt GeoCatalog-webbprogram följer den här arkitekturen:

Diagram som visar arkitekturen för ett GeoCatalog-webbprogram med en webbläsarklient som ansluter till Microsoft Entra-ID för autentisering och till GeoCatalog-API:er för dataåtkomst.

Registrera ditt program i Microsoft Entra-ID

Innan webbprogrammet kan autentisera användare registrerar du det i Microsoft Entra-ID. Den här snabbstarten använder en SPA-registrering (Single Page Application), som är perfekt för JavaScript-program på klientsidan och lokal utveckling. API-integreringsmönstren som visas i senare steg fungerar med alla programtyper.

Anmärkning

För produktionsapplikationer med en backend-server bör du överväga att välja en annan registreringstyp (Web, Native osv.). Se Konfigurera programautentisering för vägledning om hur du väljer rätt metod för ditt scenario.

Registrera som en enkeltsidesapplikation

  1. Gå till Microsoft Entra-ID i Azure-portalen.
  2. Välj Appregistreringar på sidopanelen.
  3. Välj Ny registrering.
  4. Ange ett namn för ditt program (till exempel "GeoCatalog Web App").
  5. Under Kontotyper som stöds, välj Endast konton i den här organisationskatalogen.
  6. Under Omdirigerings-URI väljer du Enkelsidigt program (SPA) och anger din utvecklings-URL (till exempel http://localhost:5173).
  7. Välj Registrera.

Observera följande värden på sidan Översikt efter registreringen:

  • Applikations-ID (klient)
  • Katalog-ID (hyresgäst)

Mer information finns i snabbstartsguide för appregistrering.

Bevilja API-behörigheter

Ditt program behöver behörighet att anropa GeoCatalog-API:et för inloggade användare:

  1. I appregistreringen väljer du API-behörigheter>Lägg till en behörighet.
  2. Välj API:er som min organisation använder och sök efter Azure Orbital Spatio.
  3. Välj Delegerade behörigheter och kontrollera user_impersonation.
  4. Välj Lägg till behörigheter.
  5. Om du är administratör väljer du Bevilja administratörsmedgivande för att godkänna för alla användare i din klientorganisation.

Konfigurera ditt program

Programmet behöver följande konfigurationsvärden. Hur du anger dessa värden beror på dina byggverktyg (miljövariabler, konfigurationsfiler och så vidare):

Konfiguration Värde Description
Katalog-URL https://{name}.{region}.geocatalog.spatio.azure.com Din GeoCatalog-endpunkt
Hyresgäst-ID Från appregistrering Din Microsoft Entra-klientorganisation
Klient-ID Från appregistrering Programmets klient-ID
API-omfång https://geocatalog.spatio.azure.com/.default Använd alltid det här exakta värdet

Installera beroenden

Installera Microsofts autentiseringsbibliotek (MSAL) för webbläsarprogram och ett kartbibliotek:

npm install @azure/msal-browser maplibre-gl
  • @azure/msal-browser – Hanterar OAuth 2.0-autentisering med Microsoft Entra-ID
  • maplibre-gl – Kartbibliotek med öppen källkod för panelvisualisering

Tips/Råd

Projektstruktur: Kodexemplen i den här snabbstarten är fristående funktioner som du kan ordna hur du vill. Ett vanligt mönster:

  • auth.js: MSAL-konfigurations- och tokenfunktioner
  • api.js: FUNKTIONER för STAC API, Tiler API och SAS-token
  • map.js: MapLibre-initiering och hantering av panelskikt
  • App.js eller main.js: Koppla ihop allt med ditt användargränssnitt

Varje funktion får sina beroenden (åtkomsttoken, URL:er) som parametrar, vilket gör dem enkla att integrera i alla ramverk eller projektstrukturer.

Implementera MSAL-autentisering

Skärmbild som visar autentiseringsflödet i ett exempelwebbprogram.

Konfigurera MSAL för webbläsarautentisering. I följande exempel visas mönstret för nyckelkonfiguration och tokenförvärv:

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();
}

STAC API: Frågesamlingar och objekt

GeoCatalog STAC-API:et tillhandahåller slutpunkter för identifiering och frågekörning av geospatiala data. Alla begäranden kräver ett Authorization huvud med en ägartoken som hämtats från Implementera MSAL-autentisering.

Lista samlingar

Skärmbild som visar listan över STAC-samlingar i ett exempelwebbprogram.

const API_VERSION = '2026-04-15';

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
}

Visa en lista över objekt i en samling

Skärmbild som visar listan över STAC-objekt i ett exempelwebbprogram.

const API_VERSION = '2026-04-15';

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
}

Sök mellan samlingar

Skärmbild som visar hur du använder STAC-sökningen för att returnera intressanta objekt.

const API_VERSION = '2026-04-15';

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,
});

Url:er för paneler: Skapa URL:er för kartvisualisering

Api:et GeoCatalog Tiler hanterar rasterdata som kartpaneler. Skapa panel-URL:er med följande mönster:

Enstaka objektplattor

Skärmbild som visar hur du visar paneler för ett enskilt objekt.

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

Url-builder-funktion för panel

const API_VERSION = '2026-04-15';

/**
 * 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/mosaic/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' }
);

Nyckelplattparametrar

Parameter Krävs Description
api-version Yes API-version (2026-04-15)
tileMatrixSetId Yes Använd WebMercatorQuad för webbkartor
assets Yes Tillgångsnamn som ska återges (exempel: visual, image)
colormap_name Nej Namngiven färgkarta (exempel: viridis, terrain)
rescale Nej Värdeintervall för skalning (exempel: 0,255)
asset_bidx Nej Bandindex (exempel: image\|1,2,3 för RGB)

Anmärkning

För samlingar med fyrbandsbilder (t.ex. NAIP med RGB + NIR) använder du asset_bidx=image|1,2,3 för att endast välja RGB-banden. Tile-servern kan inte koda fyra band som PNG.


Kartintegrering: Visa paneler med MapLibre GL

Kartbibliotek som MapLibre GL, Leaflet och OpenLayers kan visa rasterpaneler. Den viktigaste utmaningen är att lägga till auktoriseringshuvuden i panelbegäranden, eftersom dessa bibliotek hämtar paneler direkt.

MapLibre GL-exempel

MapLibre GL ger ett transformRequest alternativ för att mata in rubriker:

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 });
  }
}

Viktigt!

Funktionen transformRequest anropas för varje panelbegäran. Lagra åtkomsttoken i en variabel som transformRequest kan komma åt och uppdatera den när token uppdateras.


Mosaikpaneler: Visa samlingsomfattande bilder

Skärmbild som visar hur du visar mosaikpaneler för en samling.

Om du vill visa alla objekt i en samling som ett sömlöst lager registrerar du en mosaiksökning och använder det returnerade sök-ID:t:

const API_VERSION = '2026-04-15';

/**
 * 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/searches/${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()}`;
}

SAS-token: Ladda ned råtillgångar

SAS-API:et tillhandahåller tidsbegränsade token för nedladdning av råa tillgångsfiler (GeoTIFF:er, KSG:er och andra filer) direkt från Azure Blob Storage. Använd det här alternativet när du behöver de ursprungliga källfilerna i stället för renderade paneler.

Viktigt!

SAS-token aktiverar endast nedladdningar i webbläsarprogram. På grund av CORS-principer för Azure Blob Storage kan webbläsare inte läsa blobdata via JavaScript fetch(). Se avsnittet Webbläsarbegränsningar .

Skärmbild som visar hur du laddar ned tillgångar med hjälp av en SAS-token.

Hämta en SAS-token

const API_VERSION = '2026-04-15';

/**
 * 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
}

Skapa en signerad nedladdnings-URL

/**
 * 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);

Utlösa en filnedladdning

/**
 * 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');

Webbläsarbegränsningar

SAS-token fungerar annorlunda i webbläsare jämfört med kod på serversidan:

Användningsfall Browser På serversidan
Ladda ned filer (användaren väljer länk) ✅ Fungerar ✅ Fungerar
Läsa blobdata via fetch() ❌ CORS blockerad ✅ Fungerar
Bearbeta råa pixlar i JavaScript ❌ Inte möjligt ✅ Fungerar

Webbläsarnedladdningar fungerar eftersom navigeringen (klicka på länkar) kringgår CORS. Begäranden till Azure Blob Storage blockeras dock fetch() eftersom lagringskontot inte inkluderar applikationens ursprung i sin CORS-princip.

Om programmet behöver läsa och bearbeta rådata i webbläsaren implementerar du en proxy på serversidan:

Anmärkning

Följande kod är ett förenklat exempel för att illustrera proxymönstret. För produktionsprogram bör proxyslutpunkten autentisera begäranden (till exempel genom att vidarebefordra användarens ägartoken eller använda sessionsautentisering) och verifiera att användaren har behörighet att komma åt de begärda resurserna.

// ❌ 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!

Serverdelen kan hämta bloben med hjälp av SAS-token och returnera bearbetade resultat.


Utvecklingsöverväganden

CORS-support

GeoCatalog-API:er innehåller fullständigt CORS-stöd med Access-Control-Allow-Origin: *. Webbläsarbaserade program kan göra direkta begäranden till GeoCatalog från alla ursprung, inklusive http://localhost under utvecklingen. Ingen proxy eller lösning krävs.

API:t tillåter Authorization-headern i CORS-begäranden, så autentiserade fetch()-anrop fungerar direkt i webbläsarens JavaScript.

Välja rätt dataåtkomstmetod

Metod Webbläsare fetch() Nedladdningar av webbläsare På serversidan Bäst för
Tiler-API ✅ Stöds fullt ut ✅ Ja ✅ Ja Kartvisualisering
SAS-token ❌ CORS blockerad ✅ Ja ✅ Ja Raw-filnedladdningar
  • Tiler-API: Används för att visa bilder på kartor. Returnerar renderade PNG- eller WebP-paneler med fullständigt CORS-stöd. Se Panel-URL:er och Kartintegrering.

  • SAS-token: Används för att ladda ned ursprungliga källfiler (GeoTIFF:er, KSG:er). Webbläsarnedladdningar fungerar, men fetch() blockeras av CORS-principer för Azure Blob Storage. Mer information och lösningar finns i SAS-token .

Tokenförnyelse

Åtkomsttoken upphör att gälla, vanligtvis efter en timme. Ditt program bör:

  1. Hantera 401-fel genom att hämta en ny token.
  2. Använd MSAL:s tysta token-anskaffning, som automatiskt förnyar förfallna token.
  3. Uppdatera tokenreferensen som används av kartans transformRequest.

Felhantering

Hantera vanliga felscenarier:

HTTP-status Orsak Lösning
401 Token har upphört att gälla eller är ogiltig Uppdatera åtkomsttoken
404 Objektet eller samlingen hittades inte Kontrollera att ID:t finns
424 Panel utanför datautbredning Förväntat resultat – hantera situationen smidigt

Felsökning

Error Orsak Lösning
"AADSTS50011: Matchningsfel för svars-URL" Omdirigerings-URI i kod matchar inte Microsoft Entra ID-registrering Lägg till din utvecklings-URL (till exempel http://localhost:3000) som en SPA-omdirigerings-URI i din appregistrering
Felet "Ogiltig räckvidd" Använda GeoCatalog-URL i stället för API-omfång Använd https://geocatalog.spatio.azure.com/.default som omfång
401 Obehörig på panelbegäranden Mappningsbibliotek som inte innehåller autentiseringshuvuden Använd transformRequest (MapLibre) för att lägga till ägartoken. Se till att token är aktuell
Paneler överensstämmer inte med baskartan Fel kakelmatrissättning Använda tileMatrixSetId=WebMercatorQuad för Web Mercator-projektion (EPSG:3857)
"Det gick inte att avkoda bilden" Fel tillgångsnamn, flerbandsbilder eller extern datautbredning Kontrollera item_assets för giltiga namn; använd asset_bidx=image\|1,2,3 för RGB; 404/424 utanför täckning kan förekomma

Nästa steg