Scott Mitchell
4GuysFromRolla.com
S'applique à :
Microsoft® ASP.NET
Résumé : Explique comment
réécrire des URL dynamiques dans Microsoft ASP.NET.
La réécriture d'URL consiste à intercepter une
requête Web entrante et à la rediriger
automatiquement vers une autre URL. Explique les diverses
techniques d'implémentation de la réécriture
d'URL et analyse des scénarios réels de
réécriture d'URL.
Téléchargez le code source de cet
article.
Sommaire
Introduction
Utilisations courantes de la
réécriture d'URL
Que se
passe-t-il lorsqu'une requête atteint IIS
Implémentation de la réécriture
d'URL
Création d'un moteur de
réécriture d'URL
Réécriture d'URL simple avec le moteur
de réécriture d'URL
Création d'URL vraiment
« abrégeable »
Conclusion
Bibliographie
Introduction
Arrêtez-vous quelques instants pour examiner les URL de
votre site Web. Trouvez-vous des URL de type
http://votresite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary ?
Ou vous disposez peut-être d'un groupe de pages Web qui
ont été transférées d'un répertoire ou
d'un site Web vers un autre provoquant des ruptures de liens
pour les visiteurs qui ont enregistré les anciennes URL
dans un signet. Cet article porte sur l'utilisation de la
réécriture d'URL en vue de raccourcir ces
affreuses URL pour disposer d'URL significatives
mémorisables en remplaçant
http://votresite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary
par quelque chose du type
http://yoursite.com/people/sales/chuck.smith. Nous verrons
comment il est possible d'utiliser la réécriture
d'URL pour créer une erreur 404 intelligente.
La réécriture d'URL consiste à intercepter
une requête Web entrante et à la rediriger vers une
autre ressource. Lors de la réécriture d'URL, l'URL
demandée est généralement vérifiée et
redirigée vers une autre URL en fonction de sa valeur.
Lorsque, dans le cadre de la restructuration d'un site Web, par
exemple, toutes les pages du répertoire /people/ doivent
être transférées vers le répertoire
/info/employees/, vous utiliserez la réécriture d'URL
pour vérifier si une demande Web était associée
à un fichier du répertoire /people/. Si tel est le
cas, vous ne voulez pas rediriger la demande vers le même
fichier, mais dans le répertoire /info/employees/.
Avec ASP classique, la seule manière d'utiliser la
réécriture d'URL consistait à écrite un
filtre ISAPI ou à acheter un produit tiers offrant des
fonctions de réécriture d'URL. Toutefois, avec
Microsoft® ASP.NET, vous pouvez créer aisément
votre propre programme de réécriture d'URL de
différentes manières. Dans cet article, nous allons
examiner les techniques dont disposent les développeurs
ASP.NET pour implémenter la réécriture d'URL et
utiliser des applications réelles de réécriture
d'URL. Avant de nous plonger dans les spécificités
technologiques de la réécriture d'URL, examinons
quelques scénarios quotidiens dans lesquels la
réécriture d'URL peut être utilisée.
Utilisations courantes de la
réécriture d'URL
La création de sites Web ASP.NET reposant sur les
données génère souvent une seule page Web qui
affiche un sous-ensemble des données de la base de
données en fonction de paramètres de chaîne
d'interrogation. Par exemple, lors de la conception d'un site
e-commerce, une de vos tâches consiste à permettre
aux utilisateurs de naviguer dans les produits en vente. Pour
faciliter cette opération, vous pouvez créer une page
displayCategory.aspx qui affiche les produits d'une
catégorie donnée. Les produits de la catégorie
à afficher sont définis par un paramètre de
chaîne de requête, c'est-à-dire que si
l'utilisateur veut naviguer dans les articles en vente et que
tous les articles ont un ID de catégorie
(CategoryID) 5, l'utilisateur visite :
http://votresite.com/displayCategory.aspx?CategoryID=5.
La création d'un site Web avec des URL de ce type a
deux inconvénients. Tout d'abord, pour l'utilisateur,
l'URL http://votresite.com/displayCategory.aspx?CategoryID=5
est incompréhensible. L'expert en utilisation, Jakob
Neilsen recommande
de choisir des URL :
- courtes ;
- faciles à taper ;
- qui affichent la structure du site ;
- qui soient « abrégeables » pour
permettre à l'utilisateur de naviguer sur le site en
supprimant des parties de l'URL.
J'ajouterai que les URL doivent être faciles à
retenir. L'URL
http://votresite.com/displayCategory.aspx?CategoryID=5 ne
répond à aucun des critères de Neilsen et elle
n'est pas non plus facile à mémoriser. Demander aux
utilisateurs de taper des valeurs de chaînes de
requête ne facilite pas la saisie d'une URL et ne la rend
« abrégeable » que par les
développeurs Web expérimentés qui connaissent la
fonction des paramètres de chaîne d'interrogation et
leur structure de paire nom/valeur.
Une meilleure approche consiste à utiliser une URL
compréhensible mémorisable telle que
http://votresite.com/products/Widgets. En lisant simplement
l'URL vous pouvez déterminer ce qui va s'afficher :
des informations sur les articles. L'URL est aisément
mémorisable et partageable également. Je peux dire
à mon collègue d'aller sur le site
votresite.com/products/Widgets sans qu'il ait besoin de me
redemander l'URL pour afficher la page. Essayez de faire
ça avec une page Amazon.com ! L'URL apparaît
également et doit être
« abrégeable », c'est-à-dire que
si l'utilisateur tronque la fin de l'URL et tape
http://votresite.com/products, il doit pouvoir afficher la
liste de tous les produits ou au moins la liste de
toutes les catégories de produits qu'il peut afficher.
Remarque Les URL
générées par de nombreux moteurs de blog Web
constituent un bon exemple d'URL abrégeable. Pour afficher
les publications du 28 janvier 2004, vous visitez une URL de
type http://blogquelconque.com/2004/01/28. Si l'URL est
tronquée et correspond à
http://blogquelconque.com/2004/01, l'utilisateur affiche tous
les envois de janvier 2004 et si elle est tronquée
davantage pour correspondre http://blogquelconque.com/2004,
elle affiche tous les envois de l'année 2004.
Outre la simplification des URL, la réécriture
d'URL est souvent utilisée pour gérer la
restructuration de sites Web qui génèrerait autrement
un grand nombre de ruptures de liens et de signets
obsolètes.
Que se passe-t-il lorsqu'une
requête atteint IIS ?
Avant d'examiner exactement la manière
d'implémenter la réécriture d'URL, il est
important de comprendre comment IIS Microsoft® (Internet
Information Services) traite les demandes entrantes. Lorsqu'une
requête arrive sur un serveur Web IIS, IIS examine
l'extension du fichier demandé pour déterminer la
manière de traiter la demande. Les demandes peuvent
être traitées en natif par IIS (comme le sont les
pages HTML, les images et les autres types de contenus
statiques) ou IIS peut envoyer la requête à une
extension ISAPI. Une extension ISAPI est une classe
compilée non gérée qui traite une requête
Web entrante. Elle a pour fonction de générer le
contenu pour la ressource demandée.
Si, par exemple, la page Info.asp est demandée, IIS
envoie le message à l'extension ISAPI asp.dll. Cette
extension ISAPI charge alors la page ASP, l'exécute et
retourne son rendu HTML à IIS qui l'envoie au client qui
la demande. Pour les pages ASP.NET, IIS envoie le message
à l'extension ISAPI aspnet_isapi.dll. Cette extension
passe le traitement au processus de travail ASP.NET
géré qui traite la demande en retournant le rendu
HTML de la page Web ASP.NET.
Vous pouvez personnaliser IIS pour définir les
extensions associées aux extensions ISAPI. La
figure 1 montre la boîte de dialogue Configuration de
l'application de l'outil Internet Information Services
Administrative. Notez que les extensions ASP.NET (.aspx, .ascx,
.config, .asmx, .rem, .cs, .vb, etc.) sont toutes mappées
à l'extension ISAPI aspnet_isapi.dll ISAPI.
Figure 1. Mappages configurés
pour les extensions de fichiers
Une présentation approfondie de la manière dont
IIS gère les demandes entrantes n'entre pas tout à
fait dans le cadre de cet article. Pour une présentation
plus approfondie sur ce sujet, reportez-vous à l'article
Inside IIS and ASP.NET
de Michele Leroux Bustamante.
Il est important de comprendre que le moteur ASP.NET ne traite
que les demandes Web dont les extensions sont explicitement
mappées à aspnet_isapi.dll dans IIS.
Analyse des demandes avec des filtres ISAPI
Outre l'association de l'extension de fichier de la demande
Web à l'extension ISAPI appropriée, IIS exécute
d'autres tâches. IIS, par exemple, tente d'authentifier
l'utilisateur à l'origine de la demande et détermine
si l'utilisateur authentifié est autorisé à
accéder au fichier demandé. Au cours de la durée
de vie de la gestion d'une requête, IIS passe par
différents états. Pour chaque état, IIS
déclenche un événement qui peut être
géré par un programme en utilisant des filtres
ISAPI.
À l'instar des extensions ISAPI, les filtres ISAPI sont
des blocs de code non gérés installés sur le
serveur Web. Les extensions ISAPI sont conçues pour
générer la réponse à une demande de type de
fichier particulier. En revanche, les filtres ISAPI contiennent
du code pour répondre aux événements
déclenchés par IIS. Les filtres ISAPI peuvent
intercepter et même modifier les données entrantes et
sortantes. Les filtres ISAPI ont une multitude d'applications,
notamment :
- authentification et autorisation ;
- journalisation et surveillance ;
- compression HTTP ;
- réécriture d'URL.
Bien que des filtres ISAPI puissent être utilisés
pour effectuer des opérations de réécriture
d'URL, cet article porte sur l'implémentation de la
réécriture d'URL à l'aide de ASP.NET. Toutefois,
nous aborderons les compromis entre l'implémentation de la
réécriture d'URL sous la forme d'un filtre ISAPI et
l'utilisation des techniques disponibles dans ASP.NET.
Que se passe-t-il lorsqu'une demande entre dans le moteur
ASP.NET ?
Avant ASP.NET, la réécriture d'URL sur les
serveurs Web IIS devait être implémentée à
l'aide d'un filtre ISAPI. La réécriture d'URL avec
ASP.NET est possible, car le moteur ASP.NET est
étonnamment similaire à IIS. Cette similarité
existe parce que le moteur ASP.NET :
- déclenche des événements lorsqu'il traite
une demande ;
- permet à un nombre arbitraire de modules HTTP
de gérer les événements déclenchés,
comme les filtres ISAPO de IIS ;
- délègue le rendu de la ressource demandée
à un gestionnaire HTTP semblable aux extensions
SAPI d'IIS.
À l'instar d'IIS, au cours de la durée de vie
d'une demande, le moteur ASP.NET déclenche des
événements pour signaler qu'il change d'état.
L'événement BeginRequest, par exemple, est
déclenché lorsque le moteur ASP.NET répond pour
la première fois à une demande. L'événement
AuthenticateRequest est déclenché ensuite et
se produit lorsque l'identité de l'utilisateur est
établie. (Il existe beaucoup d'autres
événements : AuthorizeRequest,
ResolveRequestCache et EndRequest, entre autres.
Ces événements sont des événements de la
classe System.Web.HttpApplication. Pour plus
d'informations, consultez la documentation technique
HttpApplication Class Overview
.)
Comme nous l'avons vu dans la section précédente,
vous pouvez créer des filtres ISAPI pour répondre aux
événements déclenchés par IIS. De la
même manière, ASP.NET fournit des modules HTTP
qui peuvent répondre aux événements
déclenchés par le moteur ASP.NET. Il est possible de
configurer une application Web ASP.NET pour disposer de
plusieurs modules HTTP. Pour chaque demande traitée par le
moteur ASP.NET, chaque module HTTP configuré est
initialisé et autorisé à lier des gestionnaires
d'événements aux événements
déclenchés au cours du traitement de la demande.
Sachez qu'un certain nombre de modules HTTP incorporés est
utilisé dans chaque demande. L'un des modules HTTP
incorporés est FormsAuthenticationModule ; il
vérifie en premier lieu si des formulaires
d'authentification sont utilisés et, dans ce cas, si
l'utilisateur a été authentifié ou non. Si tel
n'est pas le cas, l'utilisateur est renvoyé directement
vers la page d'ouverture de session définie.
Rappelez-vous qu'avec IIS une demande entrante est
redirigée vers une extension ISAPI dont la fonction
consiste à retourner les données de la demande. Par
exemple, lorsqu'une demande de page WEB ASP classique arrive,
ISS remet la demande à l'extension ISAPI asp.dll qui doit
retourner le code HTML de la page ASP demandée. Le moteur
ASP.NET utilise une approche similaire. Après avoir
initialisé les modules HTTP, le moteur ASP.NET doit
déterminer le gestionnaire HTTP qui doit traiter la
demande.
Toutes les demandes qui passent par le moteur ASP.NET sont
réceptionnées par un gestionnaire HTTP ou une
fabrique (factory, en anglais) de gestionnaires HTTP (une
fabrique de gestionnaires HTTP retourne simplement une instance
d'un gestionnaire HTTP utilisée pour traiter la demande).
Le dernier gestionnaire HTTP fournit la ressource demandée
en retournant la réponse. La réponse est
renvoyée à IIS qui la renvoie à l'utilisateur
à l'origine de la demande.
ASP.NET inclut un certain nombre de gestionnaires HTTP
incorporés. Le gestionnaire PageHandlerFactory, par
exemple, est utilisé pour le rendu des pages Web ASP.NET.
Le gestionnaire WebServiceHandlerFactory est
utilisé pour le rendu des enveloppes SOAP de réponse
pour les services Web ASP.NET. Le gestionnaire
TraceHandler fournit le rendu du code HTML des demandes
à trace.axd.
La figure 2 montre le traitement d'une demande de
ressource ASP.NET. En premier lieu, ISS reçoit la demande
et l'envoie à aspnet_isapi.dll. Le moteur ASP.NET
initialise ensuite les modules HTTP configurés. Enfin, le
gestionnaire HTTP approprié est appelé et la
ressource demandée est rendue en retournant le code
généré à ISS et au client demandeur.
Figure 2. Demande de traitement
par IIS et ASP.NET
Création et enregistrement des modules et des
gestionnaires HTTP personnalisés
La création de modules et de gestionnaires HTTP
personnalisés est relativement simple ; elle implique
de créer une classe gérée qui implémente
l'interface appropriée. Les modules HTTP doivent
implémenter l'interface System.Web.IHttpModule
alors que les gestionnaires et HTTP et les fabriques de
gestionnaires HTTP doivent implémenter respectivement
l'interface System.Web.IHttpHandler et l'interface
System.Web.IHttpHandlerFactory. La création de
gestionnaires HTTP et de modules HTTP n'entre pas dans le cadre
de cet article. Reportez-vous à l'article HTTP Handlers
and HTTP Modules in ASP.NET
de Mansoor Ahmed Siddiqui qui
constitue une base solide.
Après avoir créé un module HTTP ou un
gestionnaire HTTP personnalisé, vous devez l'enregistrer
dans l'application Web. L'enregistrement des modules HTTP et
des gestionnaires HTTP de l'ensemble d'un serveur Web implique
un simple ajout au fichier machine.config ;
l'enregistrement d'un module HTTP ou d'un gestionnaire HTTP
pour une application Web implique d'ajouter quelques lignes de
code XML au fichier Web.config de l'application.
Plus précisément, pour ajouter un module HTTP
à une application Web, ajoutez les lignes suivantes dans
la section configuration/system.web du fichier
Web.config :
<httpModules>
<add type="type" name="name" />
</httpModules>
La valeur type fournit l'assembly et le nom de classe
du module, alors que la valeur name fournit un nom
convivial qui peut être utilisé pour faire
référence au module HTTP dans le fichier
Global.asax.
Les gestionnaires HTTP et les fabriques de gestionnaires
HTTP sont configurés par la balise <httpHandlers>
dans la section configuration/system.web du fichier Web.config,
comme suit :
<httpHandlers>
<add verb="verb" path="path" type="type" />
</httpHandlers>
Souvenez-vous que pour chaque demande entrante, le moteur
ASP.NET détermine le gestionnaire HTTP qui doit être
utilisé pour le rendu de la demande. Cette décision
dépend du verbe et du chemin de la demande entrante. Le
verbe définit le type de la demande HTTP (GET ou POST),
alors que le chemin spécifie l'emplacement et le nom du
fichier demandé. Ainsi, si nous voulons qu'un gestionnaire
HTTP traite toutes les demandes (GET ou POST) de fichiers avec
l'extension .scott, nous devons ajouter les lignes suivantes
dans le fichier Web.config :
<httpHandlers>
<add verb="*" path="*.scott" type="type" />
</httpHandlers>
où type correspond au type du gestionnaire
HTTP.
Remarque Lorsque vous enregistrer
des gestionnaires HTTP, il est important de s'assurer que les
extensions utilisées par le gestionnaire sont
mappées au moteur ASP.NET dans IIS. Ainsi, dans le cas
de l'exemple .scott , si l'extension .scott n'est pas
associée à l'extension ISAPI aspnet_isapi.dll dans
IIS, une demande du fichier foo.scott amène IIS à
tenter de retourner le contenu du fichier foo.scott. Pour que
le gestionnaire HTTP puisse traiter cette demande,
l'extension .scott doit être associée au moteur
ASP.NET. Le moteur ASP.NET envoie ensuite la demande
correctement au gestionnaire HTTP approprié.
Pour plus d'informations sur l'enregistrement des modules
HTTP et des gestionnaires HTTP, reportez-vous à la
documentation de l'élément <httpModules>
et à la
documentation de l'élément <httpHandlers>
.
Implémentation de la
réécriture d'URL
La réécriture d'URL peut être
implémentée avec des filtres ISAPI sur le serveur Web
ISS ou avec des modules HTTP ou des gestionnaires HTTP au
niveau ASP.NET. Cet article porte sur l'implémentation de
la réécriture d'URL avec ASP.NET. Nous n'aborderons
donc pas l'implémentation d'URL à l'aide de filtres
ISAPI. Toutefois, il existe une multitude de filtres ISAPI
tiers associés à la réécriture d'URL, tels
que :
Il est possible d'implémenter la réécriture
d'URL au niveau ASP.NET via la méthode
RewritePath() de la classe
System.Web.HttpContext. La classe HttpContext
contient des informations HTTP sur une demande HTTP
donnée. Pour chaque demande que reçoit le moteur
ASP.NET, une instance HttpContext est créée
pour la demande. Cette classe a des propriétés de
type : Request et Response qui permettent
d'accéder à la demande entrante et à la
réponse sortante, Application et Session qui
permettent d'accéder aux variables de l'application et de
la session, User qui fournit des informations sur
l'utilisateur authentifié, et d'autres
propriétés associées.
Avec
Microsoft® .NET Framework Version 1.0,
la méthode RewritePath() accepte une seule
chaîne, le nouveau chemin à utiliser. En interne, la
méthode RewritePath(string) de la classe
HttpContext met à jour les propriétés
Path et QueryString de l'objet Request.
Outre RewritePath(string),
.NET Framework Version 1.1 contient une autre
forme de la méthode RewritePath(), qui accepte
trois paramètres d'entrée de chaîne. Cette forme
alternative définit non seulement les propriétés
Path et QueryString de l'objet Request,
mais également les variables des membres internes
utilisés pour calculer les valeurs PhysicalPath,
PathInfo et FilePath de l'objet
Request.
Pour implémenter la réécriture d'URL dans
ASP.NET, il est nécessaire de créer un module HTTP ou
un gestionnaire HTTP qui :
- vérifie le chemin demandé pour déterminer
si l'URL doit être réécrite ;
- réécrit le chemin, si nécessaire, en
appelant la méthode RewritePath().
Imaginons que le site Web contenait des informations sur
chaque employé, accessibles via
/info/employee.aspx?empID=employeeID. Pour rendre ces URL plus
« abrégeables », nous pouvons
décider de rendre les pages des employés accessibles
à l'aide de : /people/EmployeeName.aspx. Il s'agit
d'un cas où nous voulons utiliser la réécriture
d'URL, c'est-à-dire, quand la page
/people/ScottMitchell.aspx est demandée, nous voulons
réécrire l'URL pour utiliser en fait la page
/info/employee.aspx?empID=1001.
Réécriture d'URL avec des modules HTTP
Pour exécuter la réécriture d'URL au niveau
ASP.NET, vous pouvez utiliser un module HTTP ou un gestionnaire
HTTP. Lorsque vous utilisez un module HTTP, vous devez
déterminer au cours du cycle de vie de la demande le
moment où il est nécessaire de vérifier si l'URL
doit être réécrite. À priori, cela peut
paraître un choix arbitraire, mais la décision peut
affecter l'application de manière significative et
subtile. Le choix du moment de la réécriture est
important, car les modules HTTP ASP.NET incorporés
utilisent les propriétés de l'objet Request
pour exécuter leurs tâches. (Souvenez-vous que la
réécriture du chemin modifie les valeurs des
propriétés de l'objet Request.) Ces modules
HTTP incorporés et les événements auxquels ils
s'intègrent sont énumérés
ci-dessous :
| Module HTTP | Événement | Description |
| FormsAuthenticationModule | AuthenticateRequest | Détermine si l'utilisateur est
authentifié en utilisant des formulaires
d'authentification. Si tel n'est pas le cas,
l'utilisateur est renvoyé directement vers la page
d'ouverture de session définie. |
| FileAuthorizationModule | AuthorizeRequest | Lorsque vous utilisez l'authentification
Windows, ce module HTTP vérifie si le compte
Microsoft® Windows® dispose des droits
appropriés sur la ressource demandée. |
| UrlAuthorizationModule | AuthorizeRequest | Vérifie si le demandeur peut
accéder à l'URL spécifiée.
L'autorisation d'URL est définie via les
éléments <authorization> et
<location> dans le fichier Web.config. |
Souvenez-vous que l'événement BeginRequest
se déclenche avant AuthenticateRequest qui se
déclenche avant AuthorizeRequest.
L'événement BeginRequest constitue un
emplacement adéquat pour exécuter la
réécriture d'URL. Cela implique que si l'URL doit
être réécrite, elle le sera avant que l'un des
modules HTTP incorporés s'exécute. Mais cette
approche a un inconvénient lorsque des formulaires
d'authentification sont utilisés. Si vous avez
déjà utilisé des formulaires d'authentification,
vous savez que lorsqu'un utilisateur visite une ressource
restreinte, il est redirigé automatiquement vers une page
d'ouverture de session définie. Une fois connecté,
l'utilisateur est renvoyé vers la page à laquelle il
a tenté d'accéder en premier lieu.
Si la réécriture d'URL est exécutée dans
l'événement BeginRequest ou
AuthenticateRequest, la page d'ouverture de session,
lorsqu'elle est resoumise, renvoie l'utilisateur avec la page
réécrite. Imaginons, qu'un utilisateur tape, dans son
navigateur, /people/ScottMitchell.aspx qui est
réécrit en /info/employee.aspx?empID=1001. Si
l'application Web est configurée pour utiliser des
formulaires d'authentification, l'utilisateur visite d'abord
/people/ScottMitchell.aspx, l'URL est réécrite en
/info/employee.aspx?empID=1001, puis
FormsAuthenticationModule s'exécute pour renvoyer
l'utilisateur vers la page d'ouverture de session, si
nécessaire. Toutefois, l'URL vers laquelle l'utilisateur
est renvoyé après avoir ouvert une session sera
/info/employee.aspx?empID=1001 du fait qu'il s'agissait de
l'URL de la demande au moment de l'exécution de
FormsAuthenticationModule.
De même, lorsque vous exécutez la
réécriture dans l'événement
BeginRequest ou AuthenticateRequest,
UrlAuthorizationModule voit l'URL réécrite.
Cela implique que si vous utilisez des éléments
<location> dans le fichier Web.config pour définir
les autorisations d'URL spécifiques, vous devez faire
référence à l'URL réécrite.
Pour résoudre ces subtilités, vous pouvez
décider d'exécuter la réécriture d'URL dans
l'événement AuthorizeRequest. Bien que cette
approche résolve les anomalies d'autorisation d'URL et de
formulaires d'authentification, elle introduit un nouveau
problème : les autorisations de fichier ne
fonctionnent plus. Lorsque vous utilisez l'authentification
Windows, FileAuthorizationModule vérifie si
l'utilisateur authentifié dispose des droits d'accès
appropriés à la page ASP.NET.
Supposons que des utilisateurs ne disposent pas d'un
accès fichier au niveau Windows sur
C:\Inetput\wwwroot\info\employee.aspx et qu'ils tentent
d'accéder à /info/employee.aspx?empID=1001. Dans ce
cas, ils reçoivent une erreur d'autorisation. Toutefois,
si nous transférons la réécriture d'URL vers
l'événement AuthenticateRequest, lorsque
FileAuthorizationModule vérifie les paramètres
de sécurité, il considère toujours que le
fichier demandé est /people/ScottMitchell.aspx du fait que
l'URL n'a pas encore été réécrite. En
conséquence, la vérification d'autorisation de
fichier est transmise pour permettre à l'utilisateur de
voir le contenu de l'URL réécrite,
/info/employee.aspx?empID=1001.
Alors, quand est-il nécessaire de réécrire
une URL dans un module HTTP ? Cela dépend du type
d'authentification que vous utilisez. Si vous n'utilisez pas
d'authentification, peu importe si l'URL est réécrite
dans BeginRequest, AuthenticateRequest ou
AuthorizeRequest. Si vous utilisez des formulaires
d'authentification et n'utilisez pas l'authentification
Windows, exécutez la réécriture d'URL dans la
gestion d'événements AuthorizeRequest. Enfin,
si vous utilisez l'authentification Windows, planifiez la
réécriture d'URL au cours des événements
BeginRequest ou AuthenticateRequest.
Réécriture d'URL dans les gestionnaires HTTP
La réécriture d'URL peut être également
exécutée par un gestionnaire HTTP ou une fabrique de
gestionnaires HTTP. Notez qu'un gestionnaire HTTP est une
classe chargée de générer le contenu d'un type
de demande spécifique. Une fabrique de gestionnaires HTTP
est une classe chargée de retourner une instance d'un
gestionnaire HTTP qui peut générer le contenu d'un
type de demande spécifique.
Dans cet article, nous allons aborder la création d'une
fabrique de gestionnaires HTTP de réécriture d'URL
pour des pages Web ASP.NET. Les fabriques de gestionnaires HTTP
doivent implémenter l'interface IHttpHandlerFactory
qui inclut une méthode GetHandler(). Après
avoir initialisé les modules HTTP appropriés, le
moteur ASP.NET détermine le gestionnaire HTTP ou la
fabrique de gestionnaires HTTP à appeler pour une demande
donnée. Si une fabrique de gestionnaires HTTP doit
être appelée, le moteur ASP.NET appelle la
méthode GetHandler() de la fabrique de
gestionnaires HTTP pour passer l'objet HttpContext de la
demande Web avec d'autres informations. La fabrique de
gestionnaires HTTP doit ensuite retourner un objet qui
implémente le IHttpHandler qui peut traiter la
demande.
Pour exécuter la réécriture d'URL via un
gestionnaire HTTP, nous pouvons créer une fabrique de
gestionnaires HTTP dont la méthode GetHandler()
vérifie le chemin demandé pour déterminer s'il
doit être réécrit. S'il doit l'être, il
peut appeler la méthode RewritePath() transmise de
l'objet HttpContext, comme nous l'avons vu
précédemment. Enfin, la fabrique de gestionnaires
HTTP peut retourner le gestionnaire HTTP retourné par la
méthode GetCompiledPageInstance() de la classe
System.Web.UI.PageParser. (la fabrique de gestionnaires
HTTP de page Web ASP.NET incorporée
PageHandlerFactory fonctionne selon le même
principe).
Du fait que tous les modules HTTP sont initialisés
avant la fabrique de gestionnaires HTTP personnalisée
à instancier, l'utilisation d'une fabrique de
gestionnaires HTTP présente les mêmes
inconvénients que de placer la réécriture d'URL
dans les dernières étapes des événements,
c'est-à-dire que les autorisations de fichier ne
fonctionnent pas. En conséquence, si vous utilisez
l'authentification Windows et l'autorisation de fichier,
utilisez le module HTTP pour réécrire les URL.
La section suivante porte sur la création d'un moteur
de réécriture d'URL réutilisable. Après
l'analyse du moteur de réécriture d'URL, disponible
en téléchargeant cet article, nous consacrerons deux
sections à analyser des utilisations réelles de la
réécriture d'URL. Tout d'abord nous allons apprendre
à utiliser le moteur de réécriture d'URL et
étudier un exemple simple de réécriture d'URL.
Ensuite, nous utiliserons la puissance des expressions
régulières du moteur de réécriture pour
fournir des URL véritablement
« abrégeables ».
Création d'un moteur de
réécriture d'URL
Pour illustrer la manière d'implémenter la
réécriture d'URL dans une application Web ASP.NET,
j'ai créé un moteur de réécriture d'URL. Ce
moteur de réécriture fournir la fonctionnalité
suivante :
- Le développeur de pages ASP.NET qui utilise le
moteur de réécriture d'URL peut définir les
règles de réécriture dans le fichier
Web.config.
- Les règles de réécriture peuvent utiliser
des expressions régulières pour disposer de
règles de réécriture puissantes.
- La réécriture d'URL peut être
aisément configurée pour utiliser un module HTTP ou
un gestionnaire HTTP.
Dans cet article, nous allons examiner la
réécriture d'URL avec le module HTTP uniquement. Pour
savoir comment les gestionnaires HTTP peuvent être
utilisés pour la réécriture d'URL, consultez le
code téléchargeable avec cet article.
Définition des informations de configuration du moteur
de réécriture d'URL
Examinons la structure des règles de
réécriture dans le fichier Web.config. Tout d'abord,
vous devez indiquer dans le fichier Web.config si vous voulez
exécuter la réécriture d'URL avec le module HTTP
ou le gestionnaire HTTP. Dans la version
téléchargeable, le fichier Web.config contient deux
entrées mises en commentaire :
<!--
<httpModules>
<add type="URLRewriter.ModuleRewriter, URLRewriter"
name="ModuleRewriter" />
</httpModules>
-->
<!--
<httpHandlers>
<add verb="*" path="*.aspx"
type="URLRewriter.RewriterFactoryHandler, URLRewriter" />
</httpHandlers>
-->
Mettez en commentaire l'entrée <httpModules> pour
utiliser le module HTTP pour la réécriture. Mettez en
commentaire l'entrée <httpHandlers> pour utiliser le
gestionnaire HTTP pour la réécriture.
Le fichier Web.config permet d'indiquer si vous voulez
utiliser le module HTTP ou le gestionnaire HTTP et contient
également des règles de réécriture. Une
règle de réécriture est constituée de deux
chaînes : le modèle à rechercher dans l'URL
demandée et la chaîne de remplacement du modèle,
s'il existe. Ces informations sont exprimées selon la
syntaxe suivante dans le fichier Web.config :
<RewriterConfig>
<Rules>
<RewriterRule>
<LookFor>pattern to look for</LookFor>
<SendTo>string to replace pattern with</SendTo>
</RewriterRule>
<RewriterRule>
<LookFor>pattern to look for</LookFor>
<SendTo>string to replace pattern with</SendTo>
</RewriterRule>
...
</Rules>
</RewriterConfig>
Chaque règle de réécriture est exprimée
par un élément <RewriterRule>. Le
modèle à rechercher est défini par
l'élément <LookFor>, tandis que la
chaîne qui remplace le modèle figure dans
l'élément <SentTo>. Ces règles de
réécriture sont évaluées de haut en bas.
S'il existe une correspondance, l'URL est réécrite et
la recherche via les règles de réécriture
s'arrête.
Lorsque vous définissez des modèles dans
l'élément <LookFor>, notez que des
expressions régulières sont utilisées pour
établir la correspondance et le remplacement de
chaîne. (Dans un moment, nous allons étudier un
exemple réel qui explique comment rechercher un
modèle en utilisant des expressions régulières.)
Du fait que le modèle est une expression
régulière, veillez à désactiver les
caractères réservés dans les expressions
régulières. (Les caractères réservés
d'expressions régulières incluent notamment : .,
?, ^, $. Vous pouvez les désactiver en les faisant
précéder d'une barre oblique inverse ; par
exemple \. équivaut à un point littéral).
Réécriture d'URL avec un module HTTP
Créer un module HTTP est aussi simple que de créer
une classe qui implémente l'interface IHttpModule.
L'interface IHttpModule définit deux
méthodes :
- Init(HttpApplication). Cette méthode se
déclenche lorsque le module HTTP est initialisé.
Dans cette méthode, vous liez des gestionnaires
d'événements aux événements
HttpApplication appropriés.
- Dispose(). Cette méthode est appelée
lorsque la demande est terminée et a été
renvoyée à IIS. Un nettoyage final doit être
effectué à ce stade.
Pour faciliter la création d'un module HTTP pour la
réécriture d'URL, j'ai commencé par créer
la classe de base abstraite BaseModuleRewriter. Cette
classe implémente IHttpModule. Dans
l'événement Init(), elle lie
l'événement HttpApplication's
AuthorizeRequest à la méthode
BaseModuleRewriter_AuthorizeRequest. La méthode
BaseModuleRewriter_AuthorizeRequest appelle la
méthode Rewrite() de la classe en passant le
chemin demandé avec l'objet HttpApplication
transmis à la méthode Init(). La méthode
Rewrite() est abstraite, ce qui implique que dans la
classe BaseModuleRewriter, la méthode
Rewrite() ne dispose pas de corps de méthode. En
fait, la classe issue de BaseModuleRewriter doit
remplacer cette méthode et fournir un corps de
méthode.
Avec cette classe de base en place, il nous suffit
maintenant de créer une classe issue de
BaseModuleRewriter qui remplace Rewrite() et
exécute ici le code de réécriture d'URL. Le code
de BaseModuleRewriter figure ci-dessous.
public abstract class BaseModuleRewriter : IHttpModule
{
public virtual void Init(HttpApplication app)
{
// WARNING! This does not work with Windows authentication!
// If you are using Windows authentication,
// change to app.BeginRequest
app.AuthorizeRequest += new
EventHandler(this.BaseModuleRewriter_AuthorizeRequest);
}
public virtual void Dispose() {}
protected virtual void BaseModuleRewriter_AuthorizeRequest(
object sender, EventArgs e)
{
HttpApplication app = (HttpApplication) sender;
Rewrite(app.Request.Path, app);
}
protected abstract void Rewrite(string requestedPath,
HttpApplication app);
}
Notez que la classe BaseModuleRewriter exécute
la réécriture d'URL dans l'événement
AuthorizeRequest. Rappelez-vous que si vous utilisez
l'authentification Windows avec les autorisations de fichier,
vous devez modifier cela pour que la réécriture d'URL
soit exécutée dans les événements
BeginRequest ou AuthenticateRequest.
La classe ModuleRewriter étend la classe
BaseModuleRewriter et elle est chargée
d'exécuter la réécriture d'URL.
ModuleRewriter contient une seule méthode de
remplacement, Rewrite(), qui est indiquée
ci-dessous :
protected override void Rewrite(string requestedPath,
System.Web.HttpApplication app)
{
// get the configuration rules
RewriterRuleCollection rules =
RewriterConfiguration.GetConfig().Rules;
// iterate through each rule...
for(int i = 0; i < rules.Count; i++)
{
// get the pattern to look for, and
// Resolve the Url (convert ~ into the appropriate directory)
string lookFor = "^" +
RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath,
rules[i].LookFor) + "$";
// Create a regex (note that IgnoreCase is set...)
Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);
// See if a match is found
if (re.IsMatch(requestedPath))
{
// match found - do any replacement needed
string sendToUrl =
RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath,
re.Replace(requestedPath, rules[i].SendTo));
// Rewrite the URL
RewriterUtils.RewriteUrl(app.Context, sendToUrl);
break; // exit the for loop
}
}
}
La méthode Rewrite() commence par obtenir le jeu
de règles de réécriture dans le fichier
Web.config. Elle est itérée ensuite sur les
règles de réécriture une règle à la
fois, et pour chaque règle, elle obtient sa
propriété LookFor et elle utilise une
expression régulière pour déterminer si une
correspondance existe dans l'URL demandée.
Si une correspondance existe, un remplacement d'expression
régulière est exécuté dans le chemin
demandé avec la valeur de la propriété
SendTo. L'URL remplacée est alors envoyée
à la méthode RewriterUtils.RewriteUrl().
RewriterUtils est une classe d'assistance qui fournit
deux méthodes statiques utilisées par le module HTTP
et le gestionnaire HTTP de réécriture d'URL. La
méthode RewriterUrl() appelle simplement la
méthode RewriteUrl() de l'objet
HttpContext.
Remarque Vous aurez sans doute
remarqué que lors de l'établissement de la
correspondance et du remplacement à l'aide d'une
expression régulière, la méthode
RewriterUtils.ResolveUrl() est appelée. Cette
méthode d'assistance remplace simplement les instances
~ dans la chaîne par la valeur du chemin de
l'application.
Vous pouvez télécharger l'ensemble du code du
moteur de réécriture d'URL avec cet article. Nous
venons d'examiner les éléments les plus
apparentés, mais il existe également d'autres
composants, tels que des classes de désérialisation
des règles de réécriture de format XML dans le
fichier Web.config en un objet, ainsi que des groupes de
gestionnaires HTTP de réécriture d'URL. Les trois
sections restantes de cet article portent sur des utilisations
réelles de réécriture d'URL.
Réécriture d'URL
simple avec le moteur de réécriture d'URL
Pour montrer le fonctionnement du moteur de
réécriture, nous allons créer une application
Web ASP.NET qui utilise la réécriture d'URL simple.
Imaginez que vous travaillez pour une société qui
vend divers produits en ligne et qu'il existe les
catégories de produits suivantes :
| ID de catégorie | Nom de catégorie |
| 1 | Boissons |
| 2 | Condiments |
| 3 | Confections |
| 4 | Produits laitiers |
| ... | ... |
Supposons que nous avons déjà créé la
page Web ASP.NET ListProductsByCategory.aspx qui accepte une
valeur d'ID de catégorie dans la chaîne
d'interrogation et affiche tous les produits de la
catégorie. Les utilisateurs qui veulent afficher les
boissons proposées accèdent à
ListProductsByCategory.aspx?CategoryID=1 et ceux qui veulent
identifier les produits laitiers accèdent
ListProductsByCategory.aspx?CategoryID=4. Supposons
également que nous disposons de la page
ListCategories.aspx qui affiche la liste des catégories de
produits en vente.
À l'évidence, nous pouvons réécrire les
URL dans ce cas du fait que les URL présentées à
l'utilisateur n'ont aucune signification et ne fournissent pas
non plus une « vulnérabilité ».
Réécrivons les URL de sorte que, lorsque
l'utilisateur visite /Products/Beverages.aspx, l'URL soit
réécrite sous la forme
ListProductsByCategory.aspx?CategoryID=1. Nous pouvons
effectuer cette opération avec la règle de
réécriture d'URL suivante dans le fichier
Web.config :
<RewriterConfig>
<Rules>
<!-- Rules for Product Lister -->
<RewriterRule>
<LookFor>~/Products/Beverages\.aspx</LookFor>
<SendTo>~/ListProductsByCategory.aspx?CategoryID=1</SendTo>
</RewriterRule>
<RewriterRule>
</Rules>
</RewriterConfig>
Comme vous pouvez le constater, cette règle
détermine si le chemin demandé par l'utilisateur
était /Products/Beverages.aspx. Si tel est le cas, elle
réécrit l'URL sous la forme
/ListProductsByCategory.aspx?CategoryID=1.
Remarque Notez que
l'élément <LookFor> désactive le
point dans Beverages.aspx car la valeur
<LookFor> est utilisée dans un modèle
d'expression régulière et que le point, dans une
expression régulière, correspond à un
caractère spécial qui signifie
« établir une correspondance avec n'importe
quel caractère », ce qui implique que l'URL
/Products/BeveragesQaspx, par exemple, pourrait correspondre.
En désactivant le point (avec \.), nous indiquons que
nous voulons rechercher un point littéral et non un
ancien caractère.
Avec cette règle, lorsque l'utilisateur accède
à /Products/Beverages.aspx, la liste des boissons
s'affiche. La figure 3 est une capture d'écran d'un
navigateur qui accède à /Products/Beverages.aspx.
Notez que la barre d'adresse du navigateur contient l'URL
/Products/Beverages.aspx, mais que l'utilisateur voir en fait
le contenu de ListProductsByCategory.aspx?CategoryID=1 (en
fait, il n'existe aucun fichier /Products/Beverages.aspx sur le
serveur Web !).
Figure 3. Demande de
catégorie après réécriture d'URL
Comme pour /Products/Beverages.aspx, nous devons maintenant
ajouter des règles de réécriture pour les autres
catégories de produits. Il suffit d'ajouter d'autres
éléments <RewriterRule> dans
l'élément <Rules> du fichier Web.config.
Consultez le fichier Web.config que vous avez
téléchargé pour identifier le jeu de règles
complet de règles de réécriture de la
démonstration.
Pour rendre l'URL encore plus
« abrégeable », il serait
intéressant de pouvoir permettre à un utilisateur de
simplement abréger /Products/Beverages.aspx en
Beverages.aspx et d'afficher la catégorie des produits.
À première vue, la tâche semble simple ; il
suffit d'ajouter une règle de réécriture qui
associe /Products/ à /ListCategories.aspx. Toutefois, il
existe une petite subtilité ; vous devez créer
préalablement le répertoire /Products/ et y ajouter
un fichier Default.aspx vide.
Pour comprendre pourquoi il est nécessaire de
procéder ainsi, souvenez-vous que le moteur de
réécriture d'URL se trouve au niveau ASP.NET. En
fait, si le moteur ASP.NET n'a jamais la possibilité de
traiter la demande, le moteur de réécriture d'URL ne
peut pas analyser l'URL entrante. Souvenez-vous aussi que IIS
transmet les demandes entrantes au moteur ASP.NET uniquement si
le fichier demandé porte une extension appropriée.
Ainsi, si l'utilisateur accède à /Products/, IIS ne
détecte aucune extension de fichier et il vérifie si
le répertoire contient un fichier portant l'un des noms de
fichiers par défaut. (Default.aspx, Default.htm,
Default.asp, etc. Ces noms de fichiers par défaut sont
définis dans l'onglet Documents de la boîte de
dialogue des propriétés Web Server dans la boîte
de dialogue de l'outil d'administration IIS.) Naturellement, si
le répertoire /Products/ n'existe pas, IIS retourne une
erreur HTTP 404.
Il est donc nécessaire de créer le répertoire
/Products/. D'autre part, nous devons créer un seul
fichier, Default.aspx, dans ce répertoire. Ainsi, lorsque
l'utilisateur accède à /Products/, IIS analyse le
répertoire, détermine que le fichier Default.aspx
existe et transmet le traitement au moteur ASP.NET. Le
programme de réécriture d'URL réécrira
alors rapidement l'URL.
Après avoir créé le répertoire et le
fichier Default.aspx, ajoutez la règle de
réécriture suivante à l'élément
<Rules> :
<RewriterRule>
<LookFor>~/Products/Default\.aspx</LookFor>
<SendTo>~/ListCategories.aspx</SendTo>
</RewriterRule>
Une fois la règle ajoutée, l'utilisateur affiche
la liste des catégories de produits (figure 4)
lorsqu'il accède à /Products/ ou à
/Products/Default.aspx.
Figure 4. Ajout
d'« abrégeabilité » à
l'URL
Gestion des publications
Si les URL que vous réécrivez contiennent un
formulaire Web côté serveur et effectuent des
publications, l'URL sous-jacente est utilisée lors de la
publication du formulaire. En effet, si l'utilisateur tape dans
son navigateur /Products/Beverages.aspx, la barre d'adresse du
navigateur contient /Products/Beverages.aspx, mais il affiche
le contenu de ListProductsByCategory.aspx?CategoryID=1. Si
ListProductsByCategory.aspx effectue une publication,
l'utilisateur est renvoyé vers
ListProductsByCategory.aspx?CategoryID=1 et non vers
/Products/Beverages.aspx, ce qui n'a aucune conséquence
proprement dite, sauf que l'utilisateur risque d'être
surpris de voir l'URL changer soudainement en cliquant sur un
bouton.
Cette situation se produit car, lors du rendu du formulaire,
ce dernier affecte à son attribut d'action la valeur du
chemin du fichier dans l'objet Request. Naturellement,
lorsque le formulaire Web aura été rendu, l'URL
/Products/Beverages.aspx aura déjà été
convertie en ListProductsByCategory.aspx?CategoryID=1, ce qui
signifie que l'objet Request signale que l'utilisateur
visite ListProductsByCategory.aspx?CategoryID=1. Vous pouvez
résoudre ce problème en empêchant le formulaire
côté serveur de rendre un attribut d'action. (Par
défaut, les navigateurs effectuent une publication si le
formulaire ne contient pas d'attribut d'action.)
Malheureusement, le formulaire Web ne permet pas de
spécifier explicitement un attribut d'action ni de
définir une propriété pour désactiver le
rendu de l'attribut d'action. Vous devez donc étendre
vous-même la classe
System.Web.HtmlControls.HtmlForm en remplaçant la
méthode RenderAttribute() et en indiquant
explicitement qu'elle ne rende par l'attribut d'action.
Grâce à la puissance de l'héritage, nous
pouvons bénéficier de toute la fonctionnalité de
la classe HtmlForm et n'avons qu'à ajouter quelques
lignes de code pour obtenir le comportement souhaité. Le
code complet de la classe personnalisée figure
ci-après :
namespace ActionlessForm {
public class Form : System.Web.UI.HtmlControls.HtmlForm
{
protected override void RenderAttributes(HtmlTextWriter writer)
{
writer.WriteAttribute("name", this.Name);
base.Attributes.Remove("name");
writer.WriteAttribute("method", this.Method);
base.Attributes.Remove("method");
this.Attributes.Render(writer);
base.Attributes.Remove("action");
if (base.ID != null)
writer.WriteAttribute("id", base.ClientID);
}
}
}
Le code de remplacement de la méthode
RenderAttributes() contient simplement le code exact de
la méthode RenderAttributes() de la classe
HtmlForm, mais sans l'attribut d'action (j'ai
utilisé Reflector
de Lutz Roeder pour afficher le
code source de la classe HtmlForm).
Une fois cette classe créée et compilée,
ajoutez-la au dossier References de l'application Web pour
pouvoir l'utiliser dans l'application Web ASP.NET. Utilisez-la
ensuite à la place de la classe HtmlForm en
ajoutant les informations suivantes en haut de la page Web
ASP.NET :
<%@ Register TagPrefix="skm" Namespace="ActionlessForm"
Assembly="ActionlessForm" %>
Remplacez ensuite <form runat="server">
par
<skm:Form id="Form1" method="post" runat="server">
et remplacez la balise de fermeture
</form> par
</skm:Form>
Vous pouvez voir l'action de cette classe Web Form
personnalisée dans ListProductsByCategory.aspx que vous
avez téléchargé avec cet article. Le module
téléchargeable inclut également un projet Visual
Studio .NET pour le formulaire Web sans action.
Remarque Si l'URL réécrite
n'effectue pas de publication, il est inutile d'utiliser
cette classe Web Form personnalisée.
Création d'URL
véritablement « abrégeable »
La réécriture d'URL simple décrite dans la
section précédente montre la simplicité de
configuration du moteur de réécriture d'URL avec de
nouvelles règles de réécriture. La vraie
puissance des règles de réécriture se
révèle néanmoins en utilisant des expressions
régulières, comme nous allons le voir dans la section
suivante.
Les blogs connaissent un grand engouement et il semble que
tout le monde ait le sien. Si les blogs ne vous sont pas
familiers, il s'agit de pages personnelles
régulièrement mises à jour qui font office de
journal personnel en ligne. La plupart des utilisateurs de blog
commentent simplement leur journée, alors que d'autres
abordent des thèmes spécifiques tels que le
cinéma, une équipe sportive ou l'informatique.
Selon l'auteur, le blog peut être mis à jour
plusieurs fois par jour ou une fois par semaine ou toutes les
deux semaines. En règle générale, la page
d'accueil du blog contient les dix dernières entrées,
mais la plupart des programmes de création de blogs
fournissent une archive qui permet aux visiteurs d'afficher les
publications antérieures. Les blogs Web se prêtent
par excellence à la réécriture d'URL. Supposons
que lors de la consultation des archives d'un blog, vous
accédiez à l'URL /2004/02/14.aspx. Seriez-vous
vraiment surpris de lire les publications publiées le 14
février 2004 ? Vous pourriez aussi vouloir afficher
toutes les publications de février 2004 dans quel cas
voudriez tenter d'abréger l'URL à /2004/02/. Pour
afficher toutes les publications de 2004, vous pourriez tenter
d'accéder à /2004/.
Lors de la gestion d'un blog, il serait utile de fournir aux
visiteurs ce niveau
d'« abrégeabilité » d'URL. Bien
que la plupart des moteurs de blog fournissent cette
fonctionnalité, analysons comment nous pouvons
procéder en utilisant la réécriture d'URL.
Tout d'abord, nous devons utiliser une page ASP.NET qui
affiche les entrées du blog pour chaque jour, mois ou
année. Supposons que nous disposons de la page
ShowBlogContent.aspx qui utilise les paramètres de
chaîne d'interrogation Année, Mois et Jour. Pour
afficher les publications du 14 février 2004, nous pouvons
accéder à
ShowBlogContent.aspx?year=2004&month=2&day=14, pour
afficher toutes les publications de février 2004, nous
visitions ShowBlogContent.aspx?year=2004&month=2 et pour
afficher toutes les publications de l'année 2004, nous
accédons à ShowBlogContent.aspx?year=2004 (le code de
ShowBlogContent.aspx figure dans le module
téléchargeable de cet article).
Donc, si l'utilisateur accède à /2004/02/14.aspx,
nous devons réécrire l'URL en
ShowBlogContent.aspx?year=2004&month=2&day=14. Les
trois cas, lorsque l'URL définit une année, un mois
et un jour, lorsque l'URL définit uniquement l'année
et le mois et lorsque l'URL définit uniquement
l'année, peuvent être gérés avec trois
règles de réécriture :
<RewriterConfig>
<Rules>
<!-- Rules for Blog Content Displayer -->
<RewriterRule>
<LookFor>~/(\d{4})/(\d{2})/(\d{2})\.aspx</LookFor>
<SendTo>~/ShowBlogContent.aspx?year=$1&month=$2&day=$3</SendTo>
</RewriterRule>
<RewriterRule>
<LookFor>~/(\d{4})/(\d{2})/Default\.aspx</LookFor>
<SendTo><![CDATA[~/ShowBlogContent.aspx?year=$1&month=$2]]></SendTo>
</RewriterRule>
<RewriterRule>
<LookFor>~/(\d{4})/Default\.aspx</LookFor>
<SendTo>~/ShowBlogContent.aspx?year=$1</SendTo>
</RewriterRule>
</Rules>
</RewriterConfig>
Ces règles montrent la puissance des expressions
régulières. Dans la première règle, nous
recherchons une URL avec le modèle
(\d{4})/(\d{2})/(\d{2})\.aspx. En bon français, cela
correspond à une chaîne constituée de quatre
chiffres suivie d'une barre oblique suivie de deux chiffres
suivis d'une barre oblique suivie de deux chiffres suivis de
.aspx. Les parenthèses autour des groupes de chiffres sont
essentielles ; elles permettent de faire
référence aux caractères de correspondance dans
ces parenthèses dans la propriété
<SendTo> correspondante. De manière plus
spécifique, nous pouvons faire référence aux
groupes à parenthèses de correspondance en utilisant
$1, $2 et $3 pour le premier, le deuxième et le
troisième groupe à parenthèses.
Remarque Du fait que le fichier
Wb.config est de format XML, les caractères tels que
&, < et > dans la partie texte d'un
élément doivent être désactivés.
Dans l'élément <SendTo> de la
première règle, & est désactivé par
&. Dans l'élément <SendTo> de la
deuxième règle, une technique alternative est
utilisée : en utilisant un élément
<![CDATA[...]]>, il n'est pas nécessaire de
désactiver le contenu à l'intérieur. Les deux
approches sont acceptables et donnent le même
résultat.
Les figures 5, 6 et 7 montrent l'opération de
réécriture d'URL. Les données sont en fait
extraites de mon blog http://scottonwriting.net/
. La figure 5 contient les
publications du 7 novembre 2003, la figure 6 contient
toutes les publications de novembre 2003 et la figure 7,
celles de toutes les publications de 2003.
Figure 5. Publications du 7
novembre 2003
Figure 6. Toutes les publications
de novembre 2003
Figure 7. Toutes les publications
de 2003
Remarque Le moteur de
réécriture d'URL attend un modèle d'expression
régulière dans les éléments
<LookFor>. Si vous maîtrisez les
expressions régulières, lisez l'un de mes articles
précédents An
Introduction to Regular Expressions
. En outre, le site RegExLib.com
contient les expressions
régulières les plus utilisées et constitue un
référentiel pour partager vos propres expressions
régulières.
Création de la structure de répertoires
nécessaire
Lorsque /2004/03/19.aspx est demandé, IIS note
l'extension .aspx et envoie la demande au moteur ASP.NET.
Tandis que la demande transite dans le moteur ASP.NET, l'URL
est réécrite en
ShowBlogContent.aspx?year=2004&month=03&day=19 et le
visiteur affiche les entrées du 19 mars 2004 du blog. Mais
que se passe-t-il lorsqu'il accède à /2004/03/ ?
S'il n'existe pas de répertoire /2004/03/, IIS retourne
l'erreur 404. En outre, ce répertoire doit contenir une
page Default.aspx pour que la demande soit remise au moteur
ASP.NET.
Dans le cadre de cette approche, vous devez donc créer
manuellement un répertoire pour chaque année
associée à des publications et le répertoire
doit contenir une page Default.aspx. D'autre part, pour chaque
répertoire d'année, vous devez créer
manuellement douze répertoires (01, 02,
…, 12) contenant chacun un fichier
Default.aspx. (Souvenez-vous que nous avons dû
procéder ainsi, ajouter le répertoire /Products/ avec
un fichier Default.aspx, dans la démonstration
précédente pour afficher correctement
ListCategories.aspx lors de la visite de /Products/.)
À l'évidence, l'ajout d'une structure de
répertoire est rébarbatif. Pour éviter d'avoir
à le faire, il suffit d'associer les demandes IIS
entrantes au moteur ASP.NET. Ainsi, lors de l'accès à
l'URL /2004/03/, IIS enverra toujours la demande au moteur
ASP.NET, même s'il n'existe pas un répertoire
/2004/03/. Dans le cadre de cette approche, toutefois, le
moteur ASP.NET est chargé de traiter tous les types de
demandes entrantes vers le serveur Web, y compris les images,
les fichiers CSS, les fichiers externes JavaScript, les
fichiers Macromedia Flash, etc.
L'analyse détaillée du traitement de tous les
types de fichiers n'entre pas du tout dans le cadre de cet
article. Pour un exemple d'application Web ASP.NET qui utilise
cette technique, reportez-vous au moteur de blog Open Source
.Text. .Text peut être configuré pour associer
toutes les demandes au moteur ASP.NET. Il peut prendre en
charge la gestion de tous les types de fichiers en utilisant un
gestionnaire HTTP personnalisé qui sait gérer les
types de fichiers statiques types (images, fichiers CSS,
etc.).
Conclusion
Dans cet article, nous avons vu comment réécrire
des URL au niveau ASP.NET en utilisant la méthode
RewriteUrl() de la classe HttpContext. Comme nous
l'avons vu, RewriteUrl() met à jour la
propriété Request de la classe
HttpContext's, qui met à jour le fichier et le
chemin demandés. Du point de vue de l'utilisateur, le
visiteur accède à une URL, mais, en fait, une URL
différente est demandée au serveur Web.
Les URL peuvent être réécrites dans un module
HTTP ou dans un gestionnaire HTTP. Dans cet article, nous avons
examiné l'utilisation d'un module HTTP pour la
réécriture et analysé les conséquences de
la réécriture à différentes
étapes.
Naturellement, en procédant au niveau ASP.NET, la
réécriture d'URL ne peut avoir lieu que si la demande
est transmise d'IIS au moteur ASP.NET. Cela se produit
naturellement lorsque l'utilisateur demande une page ayant
l'extension .aspx. Toutefois, si vous voulez permettre à
l'utilisateur de taper une URL qui n'existe pas
réellement, mais qui est réécrite pour afficher
une page ASP.NET existante, vous devez créer des
« faux » répertoires et pages
Default.aspx ou configurer IIS pour envoyer
systématiquement toutes les demandes entrantes au moteur
ASP.NET.
Bibliographie
ASP.NET: Tips, Tutorials, and Code
Microsoft ASP.NET Coding Strategies with the Microsoft ASP.NET
Team
Essential ASP.NET with Examples in C#
Manuels consultés
La réécriture d'URL est un sujet d'attention tant
pour ASP.NET que pour les fournisseurs de technologies Web
serveur concurrents du marché. Le serveur Web Apache, par
exemple, fournit le module de réécriture d'URL mod_rewrite
. mod_rewrite est un moteur de
réécriture efficace qui fournit des règles de
réécriture en fonction de conditions, telles que des
en-têtes HTTP et des variables de serveur, ainsi que des
règles de réécriture qui utilisent des
expressions régulières. Pour plus d'informations sur
mod_rewrite, reportez-vous à A
User's Guide to URL Rewriting with the Apache Web Server
.
Il existe un certain nombre d'articles sur la
réécriture d'URL avec ASP.NET. Rewrite.NET -
A URL Rewriting Engine for .NET
porte sur un moteur de
réécriture d'URL qui émule les règles
d'expressions régulières de mod_rewrite. URL
Rewriting With ASP.NET donne également un bon
aperçu des fonctions de réécriture d'URL d'
ASP.NET. Ian Griffiths
dispose d'un
blog
sur les problèmes
associés à la réécriture d'URL avec
ASP.NET, notamment sur la publication abordée dans cet
article. Fabrice Marguerie
(
en savoir plus
) et Jason
Salas
(
en savoir plus
) disposent d'un blog sur la
réécriture d'URL pour améliorer l'emplacement
des moteurs de recherche.
À propos de l'auteur Scott Mitchell, auteur de cinq manuels et fondateur de
4GuysFromRolla.com, travaille sur les technologies Web de
Microsoft depuis cinq ans. Scott travaille comme consultant,
formateur et auteur indépendant. Vous pouvez le contacter
à l'adresse mitchell@4guysfromrolla.com
ou via son blog accessible à l'adresse http://scottonwriting.net/
.
Dernière
mise à jour le vendredi 11 juin 2004