Le fichier staticwebapp.config.json

Le fichier staticwebapp.config.json

Le fichier staticwebapp.config.json

Cet article fait partie de la série Azure Static Web Apps avec Blazor.

Un exemple complet et fonctionnel est disponible ici : mongeon/code-examples · azure-swa-blazor/02-configuration.

Dans l’article précédent, on a déployé un projet Blazor WASM sur Azure Static Web Apps avec un staticwebapp.config.json minimal. Ce fichier contenait juste le navigationFallback pour que le refresh fonctionne. Mais ce fichier peut faire beaucoup plus que ça.

Pourquoi Blazor a besoin du navigationFallback?

Blazor WASM est une SPA. Le routing se fait côté client, dans le navigateur. Quand vous cliquez sur le lien Counter dans votre app, Blazor intercepte la navigation et affiche le bon composant sans faire de requête au serveur.

Le problème arrive quand vous rafraîchissez la page ou que vous tapez directement https://monsite.com/counter dans la barre d’adresse. Là, c’est le serveur qui reçoit la requête, et il n’y a pas de fichier /counter sur le disque. Sans fallback, vous obtenez un 404.

Le navigationFallback dit au serveur : si tu ne trouves pas le fichier demandé, retourne index.html et laisse Blazor se débrouiller avec le routing.

{
  "navigationFallback": {
    "rewrite": "/index.html"
  }
}

Par contre, vous ne voulez pas que le fallback s’applique à tout. Les fichiers CSS, les images et les appels à /api/ ne devraient pas retomber sur index.html. C’est là que la propriété exclude entre en jeu :

{
  "navigationFallback": {
    "rewrite": "/index.html",
    "exclude": ["/css/*", "/images/*.{png,jpg,gif,svg}", "/api/*", "/_framework/*"]
  }
}

L’exclusion de /_framework/* est importante pour Blazor. Ce dossier contient les assemblies .NET et le runtime WebAssembly. Si le fallback intercepte une requête vers un fichier manquant dans _framework, vous allez recevoir du HTML au lieu d’un binaire et votre app va planter sans message d’erreur clair.

Contrôler les routes

La section routes permet de définir des règles qui s’appliquent aux requêtes HTTP. Les règles sont évaluées dans l’ordre du tableau, et la première qui match gagne.

Rediriger une ancienne URL vers une nouvelle, avec un code 301 pour que les moteurs de recherche suivent :

{
  "routes": [
    {
      "route": "/ancien-chemin",
      "redirect": "/nouveau-chemin",
      "statusCode": 301
    }
  ]
}

Réécrire une URL sans changer l’adresse dans le navigateur. Pratique pour servir une page spécifique sous un chemin plus propre :

{
  "routes": [
    {
      "route": "/docs",
      "rewrite": "/documentation/index.html"
    }
  ]
}

Restreindre les méthodes HTTP sur une route. Par exemple, autoriser seulement les GET sur l’API publique :

{
  "routes": [
    {
      "route": "/api/public/*",
      "methods": ["GET"],
      "allowedRoles": ["anonymous"]
    }
  ]
}

Les wildcards fonctionnent en fin de chemin seulement. /admin* va matcher /admin, /admin/users, /admin/settings, etc. C’est * sans le slash avant, ce qui inclut aussi /admin lui-même.

Ajouter des headers de sécurité

La section globalHeaders ajoute des headers HTTP à toutes les réponses. C’est l’endroit idéal pour les headers de sécurité qu’on oublie souvent :

{
  "globalHeaders": {
    "X-Content-Type-Options": "nosniff",
    "X-Frame-Options": "DENY",
    "Referrer-Policy": "strict-origin-when-cross-origin"
  }
}

Vous pouvez aussi mettre des headers sur des routes spécifiques. Les headers de route prennent le dessus sur les headers globaux quand ils sont en conflit. Par exemple, pour mettre du cache agressif sur les fichiers statiques :

{
  "routes": [
    {
      "route": "/images/*",
      "headers": {
        "Cache-Control": "public, max-age=604800, immutable"
      }
    }
  ]
}

Protéger des pages avec des rôles

SWA a deux rôles intégrés : anonymous (tout le monde) et authenticated (les utilisateurs connectés). On va voir l’authentification en détail dans un article futur, mais la config de base pour protéger une section ressemble à ça :

{
  "routes": [
    {
      "route": "/admin/*",
      "allowedRoles": ["authenticated"]
    }
  ]
}

Un utilisateur non connecté qui essaie d’accéder à /admin/ va recevoir un 401. Vous pouvez combiner ça avec un responseOverrides pour le rediriger vers la page de login plutôt que de lui montrer une erreur :

{
  "responseOverrides": {
    "401": {
      "statusCode": 302,
      "redirect": "/.auth/login/github"
    }
  }
}

On peut aussi définir des rôles personnalisés, comme administrator, et les assigner aux utilisateurs via le portail Azure ou par invitations.

Personnaliser les pages d’erreur

La section responseOverrides permet de remplacer le comportement par défaut pour les codes d’erreur HTTP. En plus du 401 qu’on vient de voir, vous pouvez personnaliser le 404 :

{
  "responseOverrides": {
    "404": {
      "rewrite": "/404.html"
    }
  }
}

Ça va servir votre propre page 404 au lieu de la page générique d’Azure. Vous pouvez créer un composant Blazor pour ça, mais assurez-vous que le fichier 404.html est un vrai fichier statique dans wwwroot, parce que le fallback ne s’applique pas aux responseOverrides.

Un exemple complet pour Blazor

En mettant tout ensemble, un staticwebapp.config.json typique pour un projet Blazor WASM ressemble à ça :

{
  "navigationFallback": {
    "rewrite": "/index.html",
    "exclude": ["/css/*", "/images/*.{png,jpg,gif,svg}", "/api/*", "/_framework/*"]
  },
  "globalHeaders": {
    "X-Content-Type-Options": "nosniff",
    "X-Frame-Options": "DENY",
    "Referrer-Policy": "strict-origin-when-cross-origin"
  },
  "routes": [
    {
      "route": "/admin/*",
      "allowedRoles": ["authenticated"]
    }
  ],
  "responseOverrides": {
    "401": {
      "statusCode": 302,
      "redirect": "/.auth/login/github"
    },
    "404": {
      "rewrite": "/404.html"
    }
  }
}

Le fichier doit être dans le dossier wwwroot de votre projet Blazor pour qu’il se retrouve dans le output de publication.

Dans le prochain article, on va brancher une API Azure Functions derrière notre Static Web App et voir comment le routing /api/ fonctionne automatiquement.

Articles de la série

  1. C’est quoi une Azure Static Web App?
  2. Le fichier staticwebapp.config.json (Cet article)
  3. Brancher une API Azure Functions
  4. L’authentification intégrée de SWA
  5. Développer localement avec le CLI swa
  6. Les preview environments sur les PR

Bon déploiement, et n’oubliez pas de tester vos routes avec un refresh avant de publier.


Cet article a été rédigé avec l’aide de l’IA et révisé par moi.


Suggestions de lecture :