Routage et chemins
Le path d'une page est l'URL à laquelle elle répond. Il est comparé littéralement, sauf s'il contient un segment :param ou *, auquel cas il devient un motif.
Formes de chemin
| Forme | Exemple | Correspond à |
|---|---|---|
| Racine | / |
La page d'accueil. |
| Statique | /about |
Ce chemin exact, et rien d'autre. |
| Imbriquée | /settings/billing |
Un nombre quelconque de segments statiques. |
| Dynamique | /blog/:slug |
Un segment, capturé sous le nom slug. |
| Catch-all | /docs/:rest* |
Le reste du chemin, capturé sous rest — doit être le dernier segment. |
| Joker | /files/* |
Tout ce qui se trouve sous /files/, sans nom de capture. |
Un chemin doit correspondre à ^/[a-z0-9-_/:*]*$ : il commence par /, et seules les minuscules sont admises. /users/:userId est rejeté — écrivez /users/:userid, ou mieux, /users/:id.
Un chemin sans : ni * est comparé comme une chaîne exacte. Aucune correspondance de préfixe — /about n'est pas la même route que /about/. Une requête portant une barre oblique finale n'est pas perdue pour autant : elle est normalisée par un 301 puis résolue à nouveau, si bien que /about/ aboutit à /about. Voir Barres obliques finales.
Segments dynamiques
Un segment :param capture exactement un segment de chemin — jamais au-delà d'un /. /blog/:slug correspond à /blog/hello mais pas à /blog/2026/hello ; utilisez /blog/:slug* pour ce dernier cas.
Les routes dynamiques sont généralement associées à un bloc collection, afin qu'une seule définition de page génère une route par enregistrement :
pages:
- name: Blog Post
path: /blog/:slug
collection: { table: posts, slugField: slug }
components:
- { type: text, element: h1, content: '$record.title' }Voir Collections et markdown pour le contrat de collection.
Routes de détail d'enregistrement
Pour servir un seul enregistrement à une URL sans générer une route par enregistrement, associez un segment dynamique à une source de données en mode single. param nomme le segment de chemin d'où lire l'identifiant :
pages:
- name: Task
path: /tasks/:id
dataSource:
table: tasks
mode: single
param: id
components:
- { type: text, element: h1, content: '$record.title' }
- { type: text, content: '$record.description' }Une requête dont le paramètre ne correspond à aucun enregistrement renvoie un 404.
$id n'est pas une syntaxe de chemin. $ n'est pas un caractère légal dans un path, donc /tasks/$id échoue à la validation. Le marqueur de segment dynamique est : partout ; $record.* est une référence de contenu, pas de route.
Le segment de langue
Sovrium ne préfixe jamais un chemin qui se résout déjà. Lorsque app.languages est configuré, le runtime lit le premier segment du chemin et, s'il correspond à un code de langue configuré, celui-ci devient la langue active pour la résolution des traductions $t:.
Les routes localisées sont donc déclarées explicitement — une page par langue, chacune portant son propre segment :
pages:
- { name: home-en, path: /en, components: [{ type: hero, content: 'hero.title' }] }
- { name: home-fr, path: /fr, components: [{ type: hero, content: 'hero.title' }] }Le seul endroit où un préfixe est ajouté est la branche 404. Un chemin sans préfixe qui ne se résout sur aucune page, mais se résoudrait une fois préfixé, reçoit un 302 vers /{lang}{chemin} au lieu d'un 404 — voir URL sans segment de langue.
Barres obliques finales
Les chemins de pages sont écrits sans barre oblique finale (path: '/about'), et cette forme sans barre est la forme canonique : c'est elle que visent tous les liens internes, les alternatives hreflang et les entrées de sitemap émis par le moteur. Une requête qui arrive avec une barre oblique finale est normalisée vers elle par un 301, puis résolue à nouveau.
| Requête | Réponse |
|---|---|
/about/ |
301 → /about |
/en/docs/ |
301 → /en/docs — la locale d'arrivée est conservée |
/docs// |
301 → /docs — les barres répétées s'effondrent en un seul saut |
/ |
200 — la racine est exemptée |
/en/ |
200 — la racine de langue nue est exemptée |
/nope/ |
404, sans en-tête Location |
La chaîne de requête entrante est reportée sur la cible à l'octet près : le suivi de campagne d'un lien entrant survit donc au saut.
Les deux exemptions ne sont pas cosmétiques. /en fait déjà l'objet d'un 301 vers /en/ (voir Langues) ; retirer la barre de /en/ pour revenir à /en ferait donc rebondir le navigateur indéfiniment entre les deux formes. Seule la racine de langue nue est exemptée — /en/docs/ est normalisé comme n'importe quel autre chemin.
La forme canonique doit se résoudre. Un 301 n'est émis que si le chemin sans barre finale répond réellement — directement, ou via le repli sur les chemins sans préfixe. /nope/ reste donc un 404 net plutôt que de devenir un 301 vers un 404, qui gaspille la redirection, échoue quand même et conduit un robot d'indexation dans une impasse.
Une page peut aussi être déclarée avec une barre oblique finale : path: '/docs/' est légal, et une requête vers /docs/ est alors servie sur place plutôt que normalisée. La configuration fait autorité.
La canonicalisation ne révèle jamais une page que vous ne pouvez pas lire. Un 301 ou un 302 de canonicalisation n'est émis que vers une page qu'un visiteur anonyme peut ouvrir. Si /vault est protégée par un rôle, /vault/ répond 404 — exactement comme un chemin qui n'aurait jamais été déclaré. Rediriger annoncerait l'existence de /vault, précisément le fait que son propre 404 sert à masquer. Le coût est que cette commodité ne s'étend à aucune page protégée, que le visiteur soit authentifié ou non : la vérification a lieu dans le routeur, qui n'a pas de session.
Ordre de résolution
Une requête entrante est traitée par le premier élément correspondant :
- Un fichier réel du répertoire public.
- Une règle de redirection.
- Un chemin de page — comparé exactement, y compris une barre oblique finale écrite dans le
path. - La normalisation de la barre oblique finale — un
301vers le chemin sans barre, lorsque celui-ci se résout. - Le repli de langue sur les chemins sans préfixe — un
302vers/{lang}{chemin}, lorsque celui-ci se résout. - Le fourre-tout 404.
Les étapes 4 et 5 ne s'exécutent que là où l'étape 3 a décliné : toute URL qui se résout aujourd'hui continue donc de se résoudre à l'octet près. Elles se composent également : /docs/ reçoit un 301 → /docs, et la requête suivante reçoit un 302 → /en/docs.
Les deux fonctionnent uniquement en mode serveur. sovrium build n'émet aucune redirection, de sorte qu'un site hébergé statiquement répond à /about/ et /docs selon ce que son hébergeur est configuré pour faire.
Pages connexes
- Présentation des pages — le tableau complet des propriétés de page.
- Collections et markdown — une route par enregistrement.
- Liaison de données —
mode: singleetparam. - Redirections — retirer un chemin sans casser les liens.
- Langues — configurer les codes de langue et les clés
$t:.
Dernière mise à jour 1 septembre 2026
Cette documentation a été rédigée avec de l'IA : des erreurs ou du contenu obsolète sont donc possibles. Sovrium est en bêta. Les contributions et corrections sont les bienvenues.