Intergiciel (middleware) de réécriture d’URL dans ASP.NET Core

Par Kirk Larkin et Rick Anderson

Cet article présente la réécriture d’URL avec des instructions sur la façon d’utiliser l’intergiciel (middleware) de réécriture d’URL dans les applications ASP.NET Core.

La réécriture d’URL consiste à modifier des URL de requête en fonction d’une ou de plusieurs règles prédéfinies. La réécriture d’URL crée une abstraction entre les emplacements des ressources et leurs adresses pour que les emplacements et les adresses ne soient pas étroitement liés. La réécriture d’URL est utile dans plusieurs scénarios pour :

  • Déplacer ou remplacer de façon temporaire ou permanente les ressources d’un serveur, tout en conservant des localisateurs stables pour ces ressources.
  • Diviser le traitement des requêtes entre différentes applications ou entre différentes parties d’une même application.
  • Supprimer, ajouter ou réorganiser les segments d’URL sur des requêtes entrantes.
  • Optimiser les URL publiques pour l’optimisation du référencement d’un site auprès d’un moteur de recherche (SEO).
  • Permettre l’utilisation des URL publiques conviviales pour aider les visiteurs à prédire le contenu retourné en demandant une ressource.
  • Rediriger des requêtes non sécurisées vers des points de terminaison sécurisés.
  • Empêcher les liaisons à chaud, où un site externe utilise une ressource statique hébergée sur un autre site en liant la ressource dans son propre contenu.

La réécriture d’URL peut réduire les performances d’une application. Limitez le nombre et la complexité des règles.

Redirection d’URL et réécriture d’URL

La différence de formulation entre la redirection d’URL et la réécriture d’URL est subtile, mais elle a des implications importantes sur la fourniture de ressources aux clients. L’intergiciel de réécriture d’URL d’ASP.NET Core est capables de répondre aux besoins des deux.

Une redirection d’URL implique une opération côté client, où le client est invité à accéder à une ressource à une autre adresse que celle demandée à l’origine. Ceci nécessite un aller-retour avec le serveur. L’URL de redirection retournée au client s’affiche dans la barre d’adresse du navigateur quand le client effectue une nouvelle requête pour la ressource.

Si /resource est redirigée vers /different-resource, le serveur répond que le client doit obtenir la ressource à l’emplacement /different-resource avec un code d’état indiquant que la redirection est temporaire ou permanente.

A WebAPI service endpoint has been temporarily changed from version 1 (v1) to version 2 (v2) on the server. A client makes a request to the service at the version 1 path /v1/api. The server sends back a 302 (Found) response with the new, temporary path for the service at version 2 /v2/api. The client makes a second request to the service at the redirect URL. The server responds with a 200 (OK) status code.

Lors de la redirection des requêtes vers une URL différente, indiquez si la redirection est permanente ou temporaire en spécifiant le code d’état avec la réponse :

  • Le code d’état 301 - Moved Permanently est utilisé quand la ressource a une nouvelle URL permanente et que toutes les requêtes futures pour la ressource doivent utiliser la nouvelle URL. Le client peut mettre en cache et réutiliser la réponse quand un code d’état 301 est reçu.

  • Le code d’état 302 - Found est utilisé quand la redirection est temporaire ou généralement susceptible d’être modifiée. Le code d’état 302 indique au client de ne pas stocker l’URL et de ne plus l’utiliser.

Pour plus d’informations sur les codes d’état, consultez RFC 9110: Status Code Definitions.

Une réécriture d’URL est une opération côté serveur qui fournit une ressource à partir d’une adresse de ressource différente de celle demandée par le client. La réécriture d’URL ne nécessite pas d’aller-retour avec le serveur. L’URL réécrite n’est pas retournée au client et n’apparaît pas dans la barre d’adresse du navigateur.

Si /resource est réécrite en /different-resource, le serveur récupère la ressource en interne à l’emplacement /different-resource.

Même si le client peut récupérer la ressource à l’URL réécrite, il n’est pas informé que la ressource existe à l’URL réécrite quand il fait sa requête et reçoit la réponse.

A WebAPI service endpoint has been changed from version 1 (v1) to version 2 (v2) on the server. A client makes a request to the service at the version 1 path /v1/api. The request URL is rewritten to access the service at the version 2 path /v2/api. The service responds to the client with a 200 (OK) status code.

Exemple d’application de réécriture d’URL

Explorez les fonctionnalités de l’intergiciel de réécriture d’URL avec l’exemple d’application. L’application applique des règles de redirection et de réécriture, et montre l’URL redirigée ou réécrite pour plusieurs scénarios.

Quand utiliser l’intergiciel (middleware) de réécriture d’URL

Utilisez l’intergiciel de réécriture d’URL lorsque les approches suivantes ne sont pas satisfaisantes :

Utilisez l’intergiciel de réécriture d’URL lorsque l’application est hébergée sur un serveur HTTP.sys.

Les principales raisons d’utiliser les technologies de réécriture d’URL basée sur le serveur dans IIS, Apache et Nginx sont les suivantes :

  • Le middleware ne prend pas en charge toutes les fonctionnalités de ces modules.

    Certaines des fonctionnalités des modules serveur ne fonctionnent pas avec les projets ASP.NET Core, comme les contraintes IsFile et IsDirectory du module Réécriture IIS. Dans ces scénarios, utilisez plutôt l’intergiciel.

  • Les performances du middleware ne correspondent probablement pas à celles des modules.

    Mener des tests de performances est la seule façon de savoir exactement quelle approche dégrade le plus les performances ou si la dégradation des performances est négligeable.

Extension et options

Établissez des règles de réécriture et de redirection d’URL en créant une instance de la classe RewriteOptions avec des méthodes d’extension pour chacune des règles de réécriture. Chaînez plusieurs règles dans l’ordre dans lequel elles doivent être traitées. Les RewriteOptions sont passées dans le middleware de réécriture d’URL quand il est ajouté au pipeline de requête avec UseRewriter :

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

Dans le code précédent, MethodRules est une classe définie par l’utilisateur. Pour plus d’informations, consultez RewriteRules.cs dans cet article.

Redirection de demandes non-www en demandes www

Trois options permettent à l’application de rediriger des demandes non-www en demandes www :

  • AddRedirectToWwwPermanent : Redirige de façon permanente la requête vers le sous-domaine www si la requête n’est pas de type www. Redirige avec un code d’état Status308PermanentRedirect.

  • AddRedirectToWww : Redirige la requête vers le sous-domaine www si la requête entrante n’est pas de type www. Redirige avec un code d’état Status307TemporaryRedirect. Une surcharge vous permet de fournir le code d’état pour la réponse. Utilisez un champ de la classe StatusCodes pour une affectation de code d’état.

Redirection d’URL

Utilisez AddRedirect pour rediriger des requêtes. Le premier paramètre contient l’expression régulière .NET (Regex) pour la correspondance sur le chemin d’accès de l’URL entrante. Le deuxième paramètre est la chaîne de remplacement. Le troisième paramètre, le cas échéant, spécifie le code d’état. Si le code d’état n’est pas spécifié, sa valeur par défaut est 302 - Trouvé, ce qui indique que la ressource est temporairement déplacée ou remplacée.

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

Dans un navigateur dans lequel les outils de développement sont activés, effectuez une requête à l’exemple d’application avec le chemin /redirect-rule/1234/5678. L’expression régulière établit une correspondance avec le chemin de la requête sur redirect-rule/(.*), et le chemin est remplacé par /redirected/1234/5678. L’URL de redirection est renvoyée au client avec le code d’état 302 - Trouvé. Le navigateur effectue une nouvelle requête à l’URL de redirection, qui apparaît dans la barre d’adresse du navigateur. Comme aucune règle de l’exemple d’application ne correspond sur l’URL de redirection :

  • La deuxième requête reçoit une réponse 200 - OK de l’application.
  • Le corps de la réponse montre l’URL de redirection.

Un aller-retour est effectué avec le serveur quand une URL est redirigée.

Avertissement

Soyez prudent lors de l’établissement de règles de redirection. Les règles de redirection sont évaluées à chaque requête effectuée à l’application, notamment après une redirection. Il est facile de créer accidentellement une boucle de redirections infinies.

La partie de l’expression entre parenthèses est appelée groupe de capture. Le point (.) de l’expression signifie mettre en correspondance n’importe quel caractère. L’astérisque (*) indique mettre en correspondance zéro occurrence ou plus du caractère précédent. Par conséquent, les deux derniers segments de chemin de l’URL, 1234/5678, sont capturés par le groupe de capture (.*). Toute valeur fournie dans l’URL de la requête après redirect-rule/ est capturée par ce groupe de capture unique.

Dans la chaîne de remplacement, les groupes capturés sont injectés dans la chaîne avec le signe dollar ($) suivi du numéro de séquence de la capture. La valeur du premier groupe de capture est obtenue avec $1, la deuxième avec $2, et ainsi de suite en séquence pour les groupes de capture de l’expression régulière. Comme il n’y a qu’un seul groupe capturé dans l’expression régulière dans redirect-rule/(.*), un seul groupe est injecté dans la chaîne de remplacement, à savoir $1. Quand la règle est appliquée, l’URL devient /redirected/1234/5678.

Essayez /redirect-rule/1234/5678 avec les outils de navigateur sous l’onglet Réseau.

Redirection d’URL vers un point de terminaison sécurisé

Utilisez AddRedirectToHttps pour rediriger les requêtes HTTP vers le même hôte et le même chemin avec le protocole HTTPS. Si le code d’état n’est pas fourni, le middleware utilise par défaut 302 - Trouvé. Si le port n’est pas fourni :

  • Le middleware utilise par défaut null.
  • Le schéma change en https (protocole HTTPS), et le client accède à la ressource sur le port 443.

L’exemple suivant montre comment définir le code d’état sur 301 - Moved Permanently et comment remplacer le port par le port HTTPS utilisé par Kestrel sur localhost. En production, le port HTTPS est défini sur null :

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

int? localhostHTTPSport = null;
if (app.Environment.IsDevelopment())
{
    localhostHTTPSport = Int32.Parse(Environment.GetEnvironmentVariable(
                   "ASPNETCORE_URLS")!.Split(new Char[] { ':', ';' })[2]);
}

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        // localhostHTTPport not needed for production, used only with localhost.
        .AddRedirectToHttps(301, localhostHTTPSport)
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

Utilisez AddRedirectToHttpsPermanent pour rediriger les requêtes non sécurisées vers le même hôte et le même chemin avec le protocole HTTPS sécurisé sur le port 443. L’intergiciel définit le code d’état sur 301 - Moved Permanently.

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

Remarque

Si vous effectuez une redirection vers un point de terminaison sécurisé et que vous n’avez pas besoin de règles de redirection supplémentaires, nous vous recommandons d’utiliser le middleware de redirection HTTPS. Pour plus d’informations, consultez Appliquer le protocole HTTPS.

L’exemple d’application montre comment utiliser AddRedirectToHttps ou AddRedirectToHttpsPermanent. Effectuez une requête HTTP non sécurisée à l’application http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz. Lors du test de la redirection HTTP vers HTTPS avec localhost :

  • Utilisez l’URL HTTP, qui a un port différent de l’URL HTTPS. L’URL HTTP se trouve dans le fichier Properties/launchSettings.json.
  • La suppression de s de https://localhost/{port} échoue, car localhost ne répond pas sur HTTP au port HTTPS.

L’image suivante montre l’image des outils de navigateur F12 d’une requête à http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz avec le code précédent :

Browser window with developer tools tracking the requests and responses: Add redirect to HTTPS

Réécrire URL

Utilisez AddRewrite pour créer une règle pour la réécriture d’URL. Le premier paramètre contient l’expression régulière pour la mise en correspondance sur le chemin de l’URL entrante. Le deuxième paramètre est la chaîne de remplacement. Le troisième paramètre, skipRemainingRules: {true|false}, indique à l’intergiciel d’ignorer, ou non, les règles de réécriture supplémentaires si la règle actuelle est appliquée.

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

Essayer la requête pour https://redirect6.azurewebsites.net/rewrite-rule/1234/5678

Le caret (^) au début de l’expression signifie que la correspondance commence au début du chemin de l’URL.

Dans l’exemple précédent avec la règle de redirection, redirect-rule/(.*), il n’existe pas de caret (^) au début de l’expression régulière. Ainsi, n’importe quel caractère peut précéder redirect-rule/ dans le chemin pour qu’une correspondance soit établie.

Chemin d’accès Correspond
/redirect-rule/1234/5678 Oui
/my-cool-redirect-rule/1234/5678 Oui
/anotherredirect-rule/1234/5678 Oui

La règle de réécriture, ^rewrite-rule/(\d+)/(\d+), établit une correspondance uniquement avec des chemins d’accès s’ils commencent par rewrite-rule/. Dans le tableau suivant, notez la différence de correspondance.

Chemin d’accès Correspond
/rewrite-rule/1234/5678 Oui
/my-cool-rewrite-rule/1234/5678 No
/anotherrewrite-rule/1234/5678 Non

À la suite de la partie ^rewrite-rule/ de l’expression se trouvent deux groupes de capture, (\d+)/(\d+). \d signifie établir une correspondance avec un chiffre (nombre). Le signe plus (+) signifie établir une correspondance avec une ou plusieurs occurrences du caractère précédent. Par conséquent, l’URL doit contenir un nombre suivi d’une barre oblique, elle-même suivie d’un autre nombre. Ces groupes sont injectés dans l’URL réécrite sous la forme $1 et $2. La chaîne de remplacement de la règle de réécriture place les groupes capturés dans la chaîne de requête. Le chemin demandé /rewrite-rule/1234/5678 est réécrit pour retourner la ressource à l’emplacement /rewritten?var1=1234&var2=5678. Si une chaîne de requête est présente dans la requête d’origine, elle est conservée lors de la réécriture de l’URL.

Il n’y a pas d’aller-retour avec le serveur pour retourner la ressource. Si la ressource existe, elle est récupérée et retournée au client avec le code d’état 200 - OK. Comme le client n’est pas redirigé, l’URL dans la barre d’adresse du navigateur ne change pas. Les clients ne peuvent pas détecter qu’une opération de réécriture d’URL s’est produite sur le serveur.

Conseils relatifs aux performances pour la réécriture et la redirection d’URL

Pour obtenir la réponse la plus rapide :

  • Classez vos règles de réécriture en partant de la règle la plus souvent mise en correspondance jusqu’à la règle la moins souvent mise en correspondance.
  • Quand c’est possible, utilisez skipRemainingRules: true, car la mise en correspondance de règles est un processus gourmand en ressources qui augmente le temps de réponse de l’application. Ignorez le traitement des règles restantes quand une correspondance est trouvée et qu’aucun traitement de règle supplémentaire n’est nécessaire.

Avertissement

Un utilisateur malveillant peut fournir une entrée coûteuse à traiter à RegularExpressions, provoquant une attaque par déni de service. Les API d’infrastructure ASP.NET Core qui utilisent RegularExpressions passent un délai d’expiration. Par exemple, les classes RedirectRule et RewriteRule passent toutes deux un délai d’expiration d’une seconde.

Apache mod_rewrite

Appliquez des règles Apache mod_rewrite avec AddApacheModRewrite. Vérifiez que le fichier de règles est déployé avec l’application. Pour obtenir plus d’informations et des exemples de règles mod_rewrite, consultez Apache mod_rewrite.

Un StreamReader est utilisé pour lire les règles dans le fichier de règles ApacheModRewrite.txt :

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

L’exemple d’application redirige les requêtes de /apache-mod-rules-redirect/(.\*) vers /redirected?id=$1. Le code d’état de la réponse est 302 - Trouvé.

# Rewrite path with additional sub directory
RewriteRule ^/apache-mod-rules-redirect/(.*) /redirected?id=$1 [L,R=302]

Essayer la requête pour https://redirect6.azurewebsites.net/apache-mod-rules-redirect/1234

L’intergiciel Apache prend en charge les variables de serveur Apache mod_rewrite suivantes :

  • CONN_REMOTE_ADDR
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_FORWARDED
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_USER_AGENT
  • HTTPS
  • IPV6
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_METHOD
  • REQUEST_SCHEME
  • REQUEST_URI
  • SCRIPT_FILENAME
  • SERVER_ADDR
  • SERVER_PORT
  • SERVER_PROTOCOL
  • TEMPS
  • TIME_DAY
  • TIME_HOUR
  • TIME_MIN
  • TIME_MON
  • TIME_SEC
  • TIME_WDAY
  • TIME_YEAR

Règles du module de réécriture d’URL IIS

Pour utiliser le même ensemble de règles que celui qui s’applique au module de réécriture d’URL IIS, utilisez AddIISUrlRewrite. Vérifiez que le fichier de règles est déployé avec l’application. N’indiquez pas au middleware d’utiliser le fichier web.config de l’application en cas d’exécution sur Windows Server IIS. Avec IIS, ces règles doivent être stockées en dehors du fichier web.config de l’application pour éviter les conflits avec le module de réécriture IIS. Pour obtenir plus d’informations et des exemples de règles du module de réécriture d’URL IIS, consultez Utilisation du module de réécriture d’URL 2.0 et Informations de référence sur la configuration du module de réécriture d’URL.

Un StreamReader est utilisé pour lire les règles dans le fichier de règles IISUrlRewrite.xml :

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

L’exemple d’application réécrit les requêtes de /iis-rules-rewrite/(.*) vers /rewritten?id=$1. La réponse est envoyée au client avec le code d’état 200 - OK.

<rewrite>
  <rules>
    <rule name="Rewrite segment to id querystring" stopProcessing="true">
      <match url="^iis-rules-rewrite/(.*)$" />
      <action type="Rewrite" url="rewritten?id={R:1}" appendQueryString="false"/>
    </rule>
  </rules>
</rewrite>

Essayer la requête pour https://redirect6.azurewebsites.net/iis-rules-rewrite/xyz

Les applications qui ont un module de réécriture IIS actif avec des règles au niveau du serveur configurées affectent l’application de manière indésirable :

  • Envisagez de désactiver le module de réécriture IIS pour l’application.
  • Pour plus d’informations, consultez Désactivation de modules IIS.

Fonctionnalités non prises en charge

L’intergiciel ne prend pas en charge les fonctionnalités de module de réécriture d’URL IIS suivantes :

  • Règles de trafic sortant
  • Variables serveur personnalisées
  • Caractères génériques
  • LogRewrittenUrl

Variables de serveur prises en charge

L’intergiciel prend en charge les variables serveur du module de réécriture d’URL IIS suivantes :

  • CONTENT_LENGTH
  • CONTENT_TYPE
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_URL
  • HTTP_USER_AGENT
  • HTTPS
  • LOCAL_ADDR
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_URI

Vous pouvez obtenir IFileProvider via un PhysicalFileProvider. Cette approche peut fournir davantage de flexibilité pour l’emplacement des fichiers de règles de réécriture. Vérifiez que les fichiers de règles de réécriture sont déployés sur le serveur dans le chemin fourni.

var fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());

Règle basée sur une méthode

Utilisez Add pour implémenter une logique de règle personnalisée dans une méthode. Add expose RewriteContext, ce qui rend HttpContext disponible pour une utilisation dans les méthodes de redirection. La propriété RewriteContext.Result détermine la façon dont un traitement du pipeline supplémentaire est géré. Définissez la valeur sur un des champs RuleResult décrits dans le tableau suivant.

Réécrire le résultat du contexte Action
RuleResult.ContinueRules (valeur par défaut) Continuer à appliquer les règles.
RuleResult.EndResponse Cesser d’appliquer les règles et envoyer la réponse.
RuleResult.SkipRemainingRules Cesser d’appliquer les règles et envoyer le contexte au middleware suivant.
using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

L’exemple d’application présente une méthode qui redirige les requêtes de chemins qui se terminent par .xml. Quand une requête est faite à /file.xml :

  • La requête est redirigée vers /xmlfiles/file.xml
  • Le code d’état est défini sur 301 - Moved Permanently. Quand le navigateur fait une nouvelle requête pour /xmlfiles/file.xml, l’intergiciel de fichiers statiques délivre le fichier au client à partir du dossier wwwroot/xmlfiles. Pour une redirection, définissez explicitement le code d’état de la réponse. Sinon, un code d’état 200 - OK est retourné et la redirection ne se produit pas sur le client.

RewriteRules.cs:

public static void RedirectXmlFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    // Because the client is redirecting back to the same app, stop 
    // processing if the request has already been redirected.
    if (request.Path.StartsWithSegments(new PathString("/xmlfiles")) ||
        request.Path.Value==null)
    {
        return;
    }

    if (request.Path.Value.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
    {
        var response = context.HttpContext.Response;
        response.StatusCode = (int) HttpStatusCode.MovedPermanently;
        context.Result = RuleResult.EndResponse;
        response.Headers[HeaderNames.Location] = 
            "/xmlfiles" + request.Path + request.QueryString;
    }
}

Cette approche peut également réécrire des requêtes. L’exemple d’application montre la réécriture du chemin pour toute requête demandant de délivrer le fichier texte file.txt à partir du dossier wwwroot. Le middleware de fichiers statiques délivre le fichier en fonction du chemin de requête mis à jour :

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

RewriteRules.cs :

public static void RewriteTextFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    if (request.Path.Value != null &&
        request.Path.Value.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
    {
        context.Result = RuleResult.SkipRemainingRules;
        request.Path = "/file.txt";
    }
}

Règle basée sur IRule

Utilisez Add pour insérer votre propre logique de règle dans une classe qui implémente l’interface IRule. IRule offre davantage de flexibilité par rapport à l’approche de la règle basée sur une méthode. La classe d’implémentation peut inclure un constructeur qui vous permet de passer des paramètres pour la méthode ApplyRule.

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)
        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

Les valeurs des paramètres dans l’exemple d’application pour extension et newPath sont vérifiées afin de remplir plusieurs conditions. extension doit contenir une valeur, laquelle doit être .png, .jpg ou .gif. Si newPath n’est pas valide, un ArgumentException est levé. Si une requête est faite pour image.png, la requête est redirigée vers /png-images/image.png. Si une requête est faite pour image.jpg, la requête est redirigée vers /jpg-images/image.jpg. Le code d’état est défini sur 301 - Moved Permanently, et context.Result est défini de façon à cesser le traitement des règles et envoyer la réponse.

public class RedirectImageRequests : IRule
{
    private readonly string _extension;
    private readonly PathString _newPath;

    public RedirectImageRequests(string extension, string newPath)
    {
        if (string.IsNullOrEmpty(extension))
        {
            throw new ArgumentException(nameof(extension));
        }

        if (!Regex.IsMatch(extension, @"^\.(png|jpg|gif)$"))
        {
            throw new ArgumentException("Invalid extension", nameof(extension));
        }

        if (!Regex.IsMatch(newPath, @"(/[A-Za-z0-9]+)+?"))
        {
            throw new ArgumentException("Invalid path", nameof(newPath));
        }

        _extension = extension;
        _newPath = new PathString(newPath);
    }

    public void ApplyRule(RewriteContext context)
    {
        var request = context.HttpContext.Request;

        // Because we're redirecting back to the same app, stop 
        // processing if the request has already been redirected
        if (request.Path.StartsWithSegments(new PathString(_newPath)) ||
            request.Path.Value == null)
        {
            return;
        }

        if (request.Path.Value.EndsWith(_extension, StringComparison.OrdinalIgnoreCase))
        {
            var response = context.HttpContext.Response;
            response.StatusCode = (int) HttpStatusCode.MovedPermanently;
            context.Result = RuleResult.EndResponse;
            response.Headers[HeaderNames.Location] = 
                _newPath + request.Path + request.QueryString;
        }
    }
}

Essayez de procéder comme suit :

  • Requête PNG : https://redirect6.azurewebsites.net/image.png
  • Requête JPG : https://redirect6.azurewebsites.net/image.jpg

Exemples d’expressions régulières

Objectif Chaîne d’expression régulière et
exemple de correspondance
Chaîne de remplacement et
Exemple de sortie
Réécrire le chemin dans la chaîne de requête ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Supprimer la barre oblique finale ^path2/(.*)/$
/path2/xyz/
$1
/path2/xyz
Appliquer une barre oblique finale ^path3/(.*[^/])$
/path3/xyz
$1/
/path3/xyz/
Éviter la réécriture des requêtes spécifiques ^(.*)(?<!\.axd)$ ou
^(?!.*\.axd$)(.*)$
Oui : /path4/resource.htm
Non : /path4/resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Réorganiser les segments d’URL path5/(.*)/(.*)/(.*)
path5/1/2/3
path5/$3/$2/$1
path5/3/2/1
Remplacer un segment d’URL ^path6/(.*)/segment2/(.*)
^path6/segment1/segment2/segment3
path6/$1/replaced/$2
/path6/segment1/replaced/segment3

Les liens du tableau précédent utilisent le code suivant déployé sur Azure :

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

using (StreamReader apacheModRewriteStreamReader =
    File.OpenText("ApacheModRewrite.txt"))
using (StreamReader iisUrlRewriteStreamReader =
    File.OpenText("IISUrlRewrite.xml"))
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent()
        .AddRedirect("redirect-rule/(.*)", "redirected/$1")
        .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2",
            skipRemainingRules: true)

        // Rewrite path to QS.
        .AddRewrite(@"^path/(.*)/(.*)", "path?var1=$1&var2=$2",
            skipRemainingRules: true)
        // Skip trailing slash.
        .AddRewrite(@"^path2/(.*)/$", "path2/$1",
            skipRemainingRules: true)
         // Enforce trailing slash.
         .AddRewrite(@"^path3/(.*[^/])$", "path3/$1/",
            skipRemainingRules: true)
         // Avoid rewriting specific requests.
         .AddRewrite(@"^path4/(.*)(?<!\.axd)$", "rewritten/$1",
            skipRemainingRules: true)
         // Rearrange URL segments
         .AddRewrite(@"^path5/(.*)/(.*)/(.*)", "path5/$3/$2/$1",
            skipRemainingRules: true)
          // Replace a URL segment
          .AddRewrite(@"^path6/(.*)/segment2/(.*)", "path6/$1/replaced/$2",
            skipRemainingRules: true)

        .AddApacheModRewrite(apacheModRewriteStreamReader)
        .AddIISUrlRewrite(iisUrlRewriteStreamReader)
        .Add(MethodRules.RedirectXmlFileRequests)
        .Add(MethodRules.RewriteTextFileRequests)
        .Add(new RedirectImageRequests(".png", "/png-images"))
        .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

    app.UseRewriter(options);
}

app.UseStaticFiles();

app.Run(context => context.Response.WriteAsync(
    $"Rewritten or Redirected Url: " +
    $"{context.Request.Path + context.Request.QueryString}"));

app.Run();

Dans la plupart des exemples d’expressions régulières précédents, le littéral path est utilisé pour créer des règles de réécriture testables uniques pour l’exemple déployé. En règle générale, l’expression régulière n’inclut pas path. Par exemple, consultez le tableau des exemples d’expressions régulières.

Ce document présente la réécriture d’URL avec des instructions sur la façon d’utiliser l’intergiciel (middleware) de réécriture d’URL dans les applications ASP.NET Core.

La réécriture d’URL consiste à modifier des URL de requête en fonction d’une ou de plusieurs règles prédéfinies. La réécriture d’URL crée une abstraction entre les emplacements des ressources et leurs adresses pour que les emplacements et les adresses ne soient pas étroitement liés. La réécriture d’URL est utile dans plusieurs scénarios pour :

  • Déplacer ou remplacer de façon temporaire ou permanente les ressources d’un serveur, tout en conservant des localisateurs stables pour ces ressources.
  • Diviser le traitement des requêtes entre différentes applications ou entre différentes parties d’une même application.
  • Supprimer, ajouter ou réorganiser les segments d’URL sur des requêtes entrantes.
  • Optimiser les URL publiques pour l’optimisation du référencement d’un site auprès d’un moteur de recherche (SEO).
  • Permettre l’utilisation des URL publiques conviviales pour aider les visiteurs à prédire le contenu retourné en demandant une ressource.
  • Rediriger des requêtes non sécurisées vers des points de terminaison sécurisés.
  • Empêcher les liaisons à chaud, où un site externe utilise une ressource statique hébergée sur un autre site en liant la ressource dans son propre contenu.

Remarque

La réécriture d’URL peut réduire les performances d’une application. Quand c’est possible, limitez le nombre et la complexité des règles.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Redirection d’URL et réécriture d’URL

La différence de formulation entre la redirection d’URL et la réécriture d’URL est subtile, mais elle a des implications importantes sur la fourniture de ressources aux clients. L’intergiciel de réécriture d’URL d’ASP.NET Core est capables de répondre aux besoins des deux.

Une redirection d’URL implique une opération côté client, où le client est invité à accéder à une ressource à une autre adresse que celle demandée à l’origine. Ceci nécessite un aller-retour avec le serveur. L’URL de redirection retournée au client s’affiche dans la barre d’adresse du navigateur quand le client effectue une nouvelle requête pour la ressource.

Si /resource est redirigée vers /different-resource, le serveur répond que le client doit obtenir la ressource à l’emplacement /different-resource avec un code d’état indiquant que la redirection est temporaire ou permanente.

A WebAPI service endpoint has been temporarily changed from version 1 (v1) to version 2 (v2) on the server. A client makes a request to the service at the version 1 path /v1/api. The server sends back a 302 (Found) response with the new, temporary path for the service at version 2 /v2/api. The client makes a second request to the service at the redirect URL. The server responds with a 200 (OK) status code.

Lors de la redirection des requêtes vers une URL différente, indiquez si la redirection est permanente ou temporaire en spécifiant le code d’état avec la réponse :

  • Le code d’état 301 - Moved Permanently est utilisé quand la ressource a une nouvelle URL permanente et que vous voulez indiquer au client que toutes les requêtes futures pour la ressource doivent utiliser la nouvelle URL. Le client peut mettre en cache et réutiliser la réponse quand un code d’état 301 est reçu.

  • Le code d’état 302 - Trouvé est utilisé quand la redirection est temporaire ou généralement susceptible d’être modifiée. Le code d’état 302 indique au client de ne pas stocker l’URL et de ne plus l’utiliser.

Pour plus d’informations sur les codes d’état, consultez RFC 9110: Status Code Definitions.

Une réécriture d’URL est une opération côté serveur qui fournit une ressource à partir d’une adresse de ressource différente de celle demandée par le client. La réécriture d’URL ne nécessite pas d’aller-retour avec le serveur. L’URL réécrite n’est pas retournée au client et n’apparaît pas dans la barre d’adresse du navigateur.

Si /resource est réécrite en /different-resource, le serveur récupère la ressource en interne à l’emplacement /different-resource.

Même si le client peut récupérer la ressource à l’URL réécrite, il n’est pas informé que la ressource existe à l’URL réécrite quand il fait sa requête et reçoit la réponse.

A WebAPI service endpoint has been changed from version 1 (v1) to version 2 (v2) on the server. A client makes a request to the service at the version 1 path /v1/api. The request URL is rewritten to access the service at the version 2 path /v2/api. The service responds to the client with a 200 (OK) status code.

Exemple d’application de réécriture d’URL

Vous pouvez explorer les fonctionnalités du middleware de réécriture d’URL avec l’exemple d’application. L’application applique des règles de redirection et de réécriture, et montre l’URL redirigée ou réécrite pour plusieurs scénarios.

Quand utiliser l’intergiciel (middleware) de réécriture d’URL

Utilisez le middleware de réécriture d’URL quand vous ne pouvez pas utiliser les approches suivantes :

Utilisez l’intergiciel de réécriture d’URL lorsque l’application est hébergée sur un serveur HTTP.sys.

Les principales raisons d’utiliser les technologies de réécriture d’URL basée sur le serveur dans IIS, Apache et Nginx sont les suivantes :

  • Le middleware ne prend pas en charge toutes les fonctionnalités de ces modules.

    Certaines des fonctionnalités des modules serveur ne fonctionnent pas avec les projets ASP.NET Core, comme les contraintes IsFile et IsDirectory du module Réécriture IIS. Dans ces scénarios, utilisez plutôt l’intergiciel.

  • Les performances du middleware ne correspondent probablement pas à celles des modules.

    Mener des tests de performances est la seule façon de savoir exactement quelle approche dégrade le plus les performances ou si la dégradation des performances est négligeable.

Package

L’intergiciel (middleware) de réécriture d’URL est fourni par le package Microsoft.AspNetCore.Rewrite, qui est implicitement inclus dans les applications ASP.NET Core.

Extension et options

Établissez des règles de réécriture et de redirection d’URL en créant une instance de la classe RewriteOptions avec des méthodes d’extension pour chacune de vos règles de réécriture. Chaînez plusieurs règles dans l’ordre dans lequel vous voulez qu’elles soient traitées. Les RewriteOptions sont passées dans le middleware de réécriture d’URL quand il est ajouté au pipeline de requête avec UseRewriter :

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

Redirection de demandes non-www en demandes www

Trois options permettent à l’application de rediriger des demandes non-www en demandes www :

  • AddRedirectToWwwPermanent : Redirige de façon permanente la requête vers le sous-domaine www si la requête n’est pas de type www. Redirige avec un code d’état Status308PermanentRedirect.

  • AddRedirectToWww : Redirige la requête vers le sous-domaine www si la requête entrante n’est pas de type www. Redirige avec un code d’état Status307TemporaryRedirect. Une surcharge vous permet de fournir le code d’état pour la réponse. Utilisez un champ de la classe StatusCodes pour une affectation de code d’état.

Redirection d’URL

Utilisez AddRedirect pour rediriger des requêtes. Le premier paramètre contient votre expression régulière pour la mise en correspondance sur le chemin de l’URL entrante. Le deuxième paramètre est la chaîne de remplacement. Le troisième paramètre, le cas échéant, spécifie le code d’état. Si vous ne spécifiez pas le code d’état, sa valeur par défaut est 302 - Trouvé, ce qui indique que la ressource est temporairement déplacée ou remplacée.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

Dans un navigateur dans lequel les outils de développement sont activés, effectuez une requête à l’exemple d’application avec le chemin /redirect-rule/1234/5678. L’expression régulière établit une correspondance avec le chemin de la requête sur redirect-rule/(.*), et le chemin est remplacé par /redirected/1234/5678. L’URL de redirection est renvoyée au client avec le code d’état 302 - Trouvé. Le navigateur effectue une nouvelle requête à l’URL de redirection, qui apparaît dans la barre d’adresse du navigateur. Comme aucune règle de l’exemple d’application ne correspond sur l’URL de redirection :

  • La deuxième requête reçoit une réponse 200 - OK de l’application.
  • Le corps de la réponse montre l’URL de redirection.

Un aller-retour est effectué avec le serveur quand une URL est redirigée.

Avertissement

Soyez prudent lors de l’établissement de règles de redirection. Les règles de redirection sont évaluées à chaque requête effectuée à l’application, notamment après une redirection. Il est facile de créer accidentellement une boucle de redirections infinies.

Requête d’origine : /redirect-rule/1234/5678

Browser window with developer tools tracking the requests and responses: Add redirect

La partie de l’expression entre parenthèses est appelée groupe de capture. Le point (.) de l’expression signifie mettre en correspondance n’importe quel caractère. L’astérisque (*) indique mettre en correspondance zéro occurrence ou plus du caractère précédent. Par conséquent, les deux derniers segments de chemin de l’URL, 1234/5678, sont capturés par le groupe de capture (.*). Toute valeur fournie dans l’URL de la requête après redirect-rule/ est capturée par ce groupe de capture unique.

Dans la chaîne de remplacement, les groupes capturés sont injectés dans la chaîne avec le signe dollar ($) suivi du numéro de séquence de la capture. La valeur du premier groupe de capture est obtenue avec $1, la deuxième avec $2, et ainsi de suite en séquence pour les groupes de capture de votre expression régulière. Comme il n’y a qu’un seul groupe capturé dans l’expression régulière de la règle de redirection de l’exemple d’application, un seul groupe est injecté dans la chaîne de remplacement, à savoir $1. Quand la règle est appliquée, l’URL devient /redirected/1234/5678.

Redirection d’URL vers un point de terminaison sécurisé

Utilisez AddRedirectToHttps pour rediriger les requêtes HTTP vers le même hôte et le même chemin avec le protocole HTTPS. Si le code d’état n’est pas fourni, le middleware utilise par défaut 302 - Trouvé. Si le port n’est pas fourni :

  • Le middleware utilise par défaut null.
  • Le schéma change en https (protocole HTTPS), et le client accède à la ressource sur le port 443.

L’exemple suivant montre comment définir le code d’état sur 301 - Moved Permanently et changer le port en 5001.

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttps(301, 5001);

    app.UseRewriter(options);
}

Utilisez AddRedirectToHttpsPermanent pour rediriger les requêtes non sécurisées vers le même hôte et le même chemin avec le protocole HTTPS sécurisé sur le port 443. L’intergiciel définit le code d’état sur 301 - Moved Permanently.

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent();

    app.UseRewriter(options);
}

Remarque

Si vous effectuez une redirection vers un point de terminaison sécurisé et que vous n’avez pas besoin de règles de redirection supplémentaires, nous vous recommandons d’utiliser le middleware de redirection HTTPS. Pour plus d’informations, consultez la rubrique Appliquer HTTPS.

L’exemple d’application peut montrer comment utiliser AddRedirectToHttps ou AddRedirectToHttpsPermanent. Ajoutez la méthode d’extension à RewriteOptions. Effectuez une requête non sécurisée à l’application à n’importe quelle URL. Ignorez l’avertissement de sécurité du navigateur indiquant que le certificat auto-signé n’est pas approuvé ou créez une exception pour approuver le certificat.

Requête d’origine utilisant AddRedirectToHttps(301, 5001) : http://localhost:5000/secure

Browser window with developer tools tracking the requests and responses: Add redirect to HTTPS

Requête d’origine utilisant AddRedirectToHttpsPermanent : http://localhost:5000/secure

Browser window with developer tools tracking the requests and responses: Add redirect to HTTPS permanent

Réécrire URL

Utilisez AddRewrite pour créer une règle pour la réécriture d’URL. Le premier paramètre contient l’expression régulière pour la mise en correspondance sur le chemin de l’URL entrante. Le deuxième paramètre est la chaîne de remplacement. Le troisième paramètre, skipRemainingRules: {true|false}, indique à l’intergiciel d’ignorer, ou non, les règles de réécriture supplémentaires si la règle actuelle est appliquée.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

Requête d’origine : /rewrite-rule/1234/5678

Browser window with developer tools tracking the request and response: Add rewrite

Le caret (^) au début de l’expression signifie que la correspondance commence au début du chemin de l’URL.

Dans l’exemple précédent avec la règle de redirection, redirect-rule/(.*), il n’existe pas de caret (^) au début de l’expression régulière. Ainsi, n’importe quel caractère peut précéder redirect-rule/ dans le chemin pour qu’une correspondance soit établie.

Chemin d’accès Correspond
/redirect-rule/1234/5678 Oui
/my-cool-redirect-rule/1234/5678 Oui
/anotherredirect-rule/1234/5678 Oui

La règle de réécriture, ^rewrite-rule/(\d+)/(\d+), établit une correspondance uniquement avec des chemins d’accès s’ils commencent par rewrite-rule/. Dans le tableau suivant, notez la différence de correspondance.

Chemin d’accès Correspond
/rewrite-rule/1234/5678 Oui
/my-cool-rewrite-rule/1234/5678 No
/anotherrewrite-rule/1234/5678 Non

À la suite de la partie ^rewrite-rule/ de l’expression se trouvent deux groupes de capture, (\d+)/(\d+). \d signifie établir une correspondance avec un chiffre (nombre). Le signe plus (+) signifie établir une correspondance avec une ou plusieurs occurrences du caractère précédent. Par conséquent, l’URL doit contenir un nombre suivi d’une barre oblique, elle-même suivie d’un autre nombre. Ces groupes sont injectés dans l’URL réécrite sous la forme $1 et $2. La chaîne de remplacement de la règle de réécriture place les groupes capturés dans la chaîne de requête. Le chemin demandé /rewrite-rule/1234/5678 est réécrit pour obtenir la ressource à l’emplacement /rewritten?var1=1234&var2=5678. Si une chaîne de requête est présente dans la requête d’origine, elle est conservée lors de la réécriture de l’URL.

Il n’y a pas d’aller-retour avec le serveur pour obtenir la ressource. Si la ressource existe, elle est récupérée et retournée au client avec le code d’état 200 - OK. Comme le client n’est pas redirigé, l’URL dans la barre d’adresse du navigateur ne change pas. Les clients ne peuvent pas détecter qu’une opération de réécriture d’URL s’est produite sur le serveur.

Remarque

Quand c’est possible, utilisez skipRemainingRules: true, car la mise en correspondance de règles est un processus gourmand en ressources qui augmente le temps de réponse de l’application. Pour obtenir la réponse d’application la plus rapide :

  • Classez vos règles de réécriture en partant de la règle la plus souvent mise en correspondance jusqu’à la règle la moins souvent mise en correspondance.
  • Ignorez le traitement des règles restantes quand une correspondance est trouvée et qu’aucun traitement de règle supplémentaire n’est nécessaire.

Apache mod_rewrite

Appliquez des règles Apache mod_rewrite avec AddApacheModRewrite. Vérifiez que le fichier de règles est déployé avec l’application. Pour obtenir plus d’informations et des exemples de règles mod_rewrite, consultez Apache mod_rewrite.

Un StreamReader est utilisé pour lire les règles dans le fichier de règles ApacheModRewrite.txt :

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

L’exemple d’application redirige les requêtes de /apache-mod-rules-redirect/(.\*) vers /redirected?id=$1. Le code d’état de la réponse est 302 - Trouvé.

# Rewrite path with additional sub directory
RewriteRule ^/apache-mod-rules-redirect/(.*) /redirected?id=$1 [L,R=302]

Requête d’origine : /apache-mod-rules-redirect/1234

Browser window with developer tools tracking the requests and responses: Add Apache mod redirect

L’intergiciel prend en charge les variables de serveur Apache mod_rewrite suivantes :

  • CONN_REMOTE_ADDR
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_FORWARDED
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_USER_AGENT
  • HTTPS
  • IPV6
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_METHOD
  • REQUEST_SCHEME
  • REQUEST_URI
  • SCRIPT_FILENAME
  • SERVER_ADDR
  • SERVER_PORT
  • SERVER_PROTOCOL
  • TEMPS
  • TIME_DAY
  • TIME_HOUR
  • TIME_MIN
  • TIME_MON
  • TIME_SEC
  • TIME_WDAY
  • TIME_YEAR

Règles du module de réécriture d’URL IIS

Pour utiliser le même ensemble de règles que celui qui s’applique au module de réécriture d’URL IIS, utilisez AddIISUrlRewrite. Vérifiez que le fichier de règles est déployé avec l’application. N’indiquez pas au middleware d’utiliser le fichier web.config de l’application en cas d’exécution sur Windows Server IIS. Avec IIS, ces règles doivent être stockées en dehors du fichier web.config de l’application pour éviter les conflits avec le module de réécriture IIS. Pour obtenir plus d’informations et des exemples de règles du module de réécriture d’URL IIS, consultez Utilisation du module de réécriture d’URL 2.0 et Informations de référence sur la configuration du module de réécriture d’URL.

Un StreamReader est utilisé pour lire les règles dans le fichier de règles IISUrlRewrite.xml :

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

L’exemple d’application réécrit les requêtes de /iis-rules-rewrite/(.*) vers /rewritten?id=$1. La réponse est envoyée au client avec le code d’état 200 - OK.

<rewrite>
  <rules>
    <rule name="Rewrite segment to id querystring" stopProcessing="true">
      <match url="^iis-rules-rewrite/(.*)$" />
      <action type="Rewrite" url="rewritten?id={R:1}" appendQueryString="false"/>
    </rule>
  </rules>
</rewrite>

Requête d’origine : /iis-rules-rewrite/1234

Browser window with developer tools tracking the request and response: Add IIS URL rewrite

Si vous avez un module de réécriture IIS actif pour lequel des règles au niveau du serveur qui affecteraient de façon non souhaitée votre application sont configurées, vous pouvez le désactiver pour une application. Pour plus d’informations, consultez Désactivation de modules IIS.

Fonctionnalités non prises en charge

L’intergiciel ne prend pas en charge les fonctionnalités de module de réécriture d’URL IIS suivantes :

  • Règles de trafic sortant
  • Variables serveur personnalisées
  • Caractères génériques
  • LogRewrittenUrl

Variables de serveur prises en charge

L’intergiciel prend en charge les variables serveur du module de réécriture d’URL IIS suivantes :

  • CONTENT_LENGTH
  • CONTENT_TYPE
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_URL
  • HTTP_USER_AGENT
  • HTTPS
  • LOCAL_ADDR
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_URI

Remarque

Vous pouvez également obtenir un IFileProvider par le biais d’un PhysicalFileProvider. Cette approche peut fournir davantage de flexibilité pour l’emplacement de vos fichiers de règles de réécriture. Vérifiez que vos fichiers de règles de réécriture sont déployés sur le serveur dans le chemin que vous fournissez.

PhysicalFileProvider fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());

Règle basée sur une méthode

Utilisez Add pour implémenter votre propre logique de règle dans une méthode. Add expose RewriteContext, ce qui rend HttpContext disponible pour une utilisation dans votre méthode. RewriteContext.Result détermine la façon dont le traitement du pipeline supplémentaire est géré. Définissez la valeur sur un des champs RuleResult décrits dans le tableau suivant.

Réécrire le résultat du contexte Action
RuleResult.ContinueRules (valeur par défaut) Continuer à appliquer les règles.
RuleResult.EndResponse Cesser d’appliquer les règles et envoyer la réponse.
RuleResult.SkipRemainingRules Cesser d’appliquer les règles et envoyer le contexte au middleware suivant.
public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

L’exemple d’application présente une méthode qui redirige les requêtes de chemins qui se terminent par .xml. Si une requête est faite pour /file.xml, la requête est redirigée vers /xmlfiles/file.xml. Le code d’état est défini sur 301 - Moved Permanently. Quand le navigateur fait une nouvelle requête pour /xmlfiles/file.xml, l’intergiciel de fichiers statiques délivre le fichier au client à partir du dossier wwwroot/xmlfiles. Pour une redirection, définissez explicitement le code d’état de la réponse. Sinon, un code d’état 200 - OK est retourné et la redirection ne se produit pas sur le client.

RewriteRules.cs :

public static void RedirectXmlFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    // Because the client is redirecting back to the same app, stop 
    // processing if the request has already been redirected.
    if (request.Path.StartsWithSegments(new PathString("/xmlfiles")))
    {
        return;
    }

    if (request.Path.Value.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
    {
        var response = context.HttpContext.Response;
        response.StatusCode = (int) HttpStatusCode.MovedPermanently;
        context.Result = RuleResult.EndResponse;
        response.Headers[HeaderNames.Location] = 
            "/xmlfiles" + request.Path + request.QueryString;
    }
}

Cette approche peut également réécrire des requêtes. L’exemple d’application montre la réécriture du chemin pour toute requête demandant de délivrer le fichier texte file.txt à partir du dossier wwwroot. Le middleware de fichiers statiques délivre le fichier en fonction du chemin de requête mis à jour :

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

RewriteRules.cs :

public static void RewriteTextFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    if (request.Path.Value.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
    {
        context.Result = RuleResult.SkipRemainingRules;
        request.Path = "/file.txt";
    }
}

Règle basée sur IRule

Utilisez Add pour insérer votre propre logique de règle dans une classe qui implémente l’interface IRule. IRule offre davantage de flexibilité par rapport à l’approche de la règle basée sur une méthode. Votre classe d’implémentation peut inclure un constructeur qui vous permet de passer des paramètres pour la méthode ApplyRule.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

Les valeurs des paramètres dans l’exemple d’application pour extension et newPath sont vérifiées afin de remplir plusieurs conditions. extension doit contenir une valeur, laquelle doit être .png, .jpg ou .gif. Si newPath n’est pas valide, un ArgumentException est levé. Si une requête est faite pour image.png, la requête est redirigée vers /png-images/image.png. Si une requête est faite pour image.jpg, la requête est redirigée vers /jpg-images/image.jpg. Le code d’état est défini sur 301 - Moved Permanently, et context.Result est défini de façon à cesser le traitement des règles et envoyer la réponse.

public class RedirectImageRequests : IRule
{
    private readonly string _extension;
    private readonly PathString _newPath;

    public RedirectImageRequests(string extension, string newPath)
    {
        if (string.IsNullOrEmpty(extension))
        {
            throw new ArgumentException(nameof(extension));
        }

        if (!Regex.IsMatch(extension, @"^\.(png|jpg|gif)$"))
        {
            throw new ArgumentException("Invalid extension", nameof(extension));
        }

        if (!Regex.IsMatch(newPath, @"(/[A-Za-z0-9]+)+?"))
        {
            throw new ArgumentException("Invalid path", nameof(newPath));
        }

        _extension = extension;
        _newPath = new PathString(newPath);
    }

    public void ApplyRule(RewriteContext context)
    {
        var request = context.HttpContext.Request;

        // Because we're redirecting back to the same app, stop 
        // processing if the request has already been redirected
        if (request.Path.StartsWithSegments(new PathString(_newPath)))
        {
            return;
        }

        if (request.Path.Value.EndsWith(_extension, StringComparison.OrdinalIgnoreCase))
        {
            var response = context.HttpContext.Response;
            response.StatusCode = (int) HttpStatusCode.MovedPermanently;
            context.Result = RuleResult.EndResponse;
            response.Headers[HeaderNames.Location] = 
                _newPath + request.Path + request.QueryString;
        }
    }
}

Requête d’origine : /image.png

Browser window with developer tools tracking the requests and responses for image.png

Requête d’origine : /image.jpg

Browser window with developer tools tracking the requests and responses for image.jpg

Exemples d’expressions régulières

Objectif Chaîne d’expression régulière et
exemple de correspondance
Chaîne de remplacement et
Exemple de sortie
Réécrire le chemin dans la chaîne de requête ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Supprimer la barre oblique finale (.*)/$
/path/
$1
/path
Appliquer une barre oblique finale (.*[^/])$
/path
$1/
/path/
Éviter la réécriture des requêtes spécifiques ^(.*)(?<!\.axd)$ ou ^(?!.*\.axd$)(.*)$
Oui : /resource.htm
Non : /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Réorganiser les segments d’URL path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Remplacer un segment d’URL ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

Ce document présente la réécriture d’URL avec des instructions sur la façon d’utiliser l’intergiciel (middleware) de réécriture d’URL dans les applications ASP.NET Core.

La réécriture d’URL consiste à modifier des URL de requête en fonction d’une ou de plusieurs règles prédéfinies. La réécriture d’URL crée une abstraction entre les emplacements des ressources et leurs adresses pour que les emplacements et les adresses ne soient pas étroitement liés. La réécriture d’URL est utile dans plusieurs scénarios pour :

  • Déplacer ou remplacer de façon temporaire ou permanente les ressources d’un serveur, tout en conservant des localisateurs stables pour ces ressources.
  • Diviser le traitement des requêtes entre différentes applications ou entre différentes parties d’une même application.
  • Supprimer, ajouter ou réorganiser les segments d’URL sur des requêtes entrantes.
  • Optimiser les URL publiques pour l’optimisation du référencement d’un site auprès d’un moteur de recherche (SEO).
  • Permettre l’utilisation des URL publiques conviviales pour aider les visiteurs à prédire le contenu retourné en demandant une ressource.
  • Rediriger des requêtes non sécurisées vers des points de terminaison sécurisés.
  • Empêcher les liaisons à chaud, où un site externe utilise une ressource statique hébergée sur un autre site en liant la ressource dans son propre contenu.

Remarque

La réécriture d’URL peut réduire les performances d’une application. Quand c’est possible, limitez le nombre et la complexité des règles.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Redirection d’URL et réécriture d’URL

La différence de formulation entre la redirection d’URL et la réécriture d’URL est subtile, mais elle a des implications importantes sur la fourniture de ressources aux clients. L’intergiciel de réécriture d’URL d’ASP.NET Core est capables de répondre aux besoins des deux.

Une redirection d’URL implique une opération côté client, où le client est invité à accéder à une ressource à une autre adresse que celle demandée à l’origine. Ceci nécessite un aller-retour avec le serveur. L’URL de redirection retournée au client s’affiche dans la barre d’adresse du navigateur quand le client effectue une nouvelle requête pour la ressource.

Si /resource est redirigée vers /different-resource, le serveur répond que le client doit obtenir la ressource à l’emplacement /different-resource avec un code d’état indiquant que la redirection est temporaire ou permanente.

A WebAPI service endpoint has been temporarily changed from version 1 (v1) to version 2 (v2) on the server. A client makes a request to the service at the version 1 path /v1/api. The server sends back a 302 (Found) response with the new, temporary path for the service at version 2 /v2/api. The client makes a second request to the service at the redirect URL. The server responds with a 200 (OK) status code.

Lors de la redirection des requêtes vers une URL différente, indiquez si la redirection est permanente ou temporaire en spécifiant le code d’état avec la réponse :

  • Le code d’état 301 - Moved Permanently est utilisé quand la ressource a une nouvelle URL permanente et que vous voulez indiquer au client que toutes les requêtes futures pour la ressource doivent utiliser la nouvelle URL. Le client peut mettre en cache et réutiliser la réponse quand un code d’état 301 est reçu.

  • Le code d’état 302 - Trouvé est utilisé quand la redirection est temporaire ou généralement susceptible d’être modifiée. Le code d’état 302 indique au client de ne pas stocker l’URL et de ne plus l’utiliser.

Pour plus d’informations sur les codes d’état, consultez RFC 9110: Status Code Definitions.

Une réécriture d’URL est une opération côté serveur qui fournit une ressource à partir d’une adresse de ressource différente de celle demandée par le client. La réécriture d’URL ne nécessite pas d’aller-retour avec le serveur. L’URL réécrite n’est pas retournée au client et n’apparaît pas dans la barre d’adresse du navigateur.

Si /resource est réécrite en /different-resource, le serveur récupère la ressource en interne à l’emplacement /different-resource.

Même si le client peut récupérer la ressource à l’URL réécrite, il n’est pas informé que la ressource existe à l’URL réécrite quand il fait sa requête et reçoit la réponse.

A WebAPI service endpoint has been changed from version 1 (v1) to version 2 (v2) on the server. A client makes a request to the service at the version 1 path /v1/api. The request URL is rewritten to access the service at the version 2 path /v2/api. The service responds to the client with a 200 (OK) status code.

Exemple d’application de réécriture d’URL

Vous pouvez explorer les fonctionnalités du middleware de réécriture d’URL avec l’exemple d’application. L’application applique des règles de redirection et de réécriture, et montre l’URL redirigée ou réécrite pour plusieurs scénarios.

Quand utiliser l’intergiciel (middleware) de réécriture d’URL

Utilisez le middleware de réécriture d’URL quand vous ne pouvez pas utiliser les approches suivantes :

Utilisez aussi le middleware quand l’application est hébergée sur le serveur HTTP.sys (anciennement appelé WebListener).

Les principales raisons d’utiliser les technologies de réécriture d’URL basée sur le serveur dans IIS, Apache et Nginx sont les suivantes :

  • Le middleware ne prend pas en charge toutes les fonctionnalités de ces modules.

    Certaines des fonctionnalités des modules serveur ne fonctionnent pas avec les projets ASP.NET Core, comme les contraintes IsFile et IsDirectory du module Réécriture IIS. Dans ces scénarios, utilisez plutôt l’intergiciel.

  • Les performances du middleware ne correspondent probablement pas à celles des modules.

    Mener des tests de performances est la seule façon de savoir exactement quelle approche dégrade le plus les performances ou si la dégradation des performances est négligeable.

Package

Pour inclure le middleware dans votre projet, ajoutez une référence de package au métapackage Microsoft.AspNetCore.App dans le fichier projet, qui contient le package Microsoft.AspNetCore.Rewrite.

Quand vous n’utilisez pas le métapackage Microsoft.AspNetCore.App, ajoutez une référence de projet au package Microsoft.AspNetCore.Rewrite.

Extension et options

Établissez des règles de réécriture et de redirection d’URL en créant une instance de la classe RewriteOptions avec des méthodes d’extension pour chacune de vos règles de réécriture. Chaînez plusieurs règles dans l’ordre dans lequel vous voulez qu’elles soient traitées. Les RewriteOptions sont passées dans le middleware de réécriture d’URL quand il est ajouté au pipeline de requête avec UseRewriter :

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

Redirection de demandes non-www en demandes www

Trois options permettent à l’application de rediriger des demandes non-www en demandes www :

  • AddRedirectToWwwPermanent : Redirige de façon permanente la requête vers le sous-domaine www si la requête n’est pas de type www. Redirige avec un code d’état Status308PermanentRedirect.

  • AddRedirectToWww : Redirige la requête vers le sous-domaine www si la requête entrante n’est pas de type www. Redirige avec un code d’état Status307TemporaryRedirect. Une surcharge vous permet de fournir le code d’état pour la réponse. Utilisez un champ de la classe StatusCodes pour une affectation de code d’état.

Redirection d’URL

Utilisez AddRedirect pour rediriger des requêtes. Le premier paramètre contient votre expression régulière pour la mise en correspondance sur le chemin de l’URL entrante. Le deuxième paramètre est la chaîne de remplacement. Le troisième paramètre, le cas échéant, spécifie le code d’état. Si vous ne spécifiez pas le code d’état, sa valeur par défaut est 302 - Trouvé, ce qui indique que la ressource est temporairement déplacée ou remplacée.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

Dans un navigateur dans lequel les outils de développement sont activés, effectuez une requête à l’exemple d’application avec le chemin /redirect-rule/1234/5678. L’expression régulière établit une correspondance avec le chemin de la requête sur redirect-rule/(.*), et le chemin est remplacé par /redirected/1234/5678. L’URL de redirection est renvoyée au client avec le code d’état 302 - Trouvé. Le navigateur effectue une nouvelle requête à l’URL de redirection, qui apparaît dans la barre d’adresse du navigateur. Comme aucune règle de l’exemple d’application ne correspond sur l’URL de redirection :

  • La deuxième requête reçoit une réponse 200 - OK de l’application.
  • Le corps de la réponse montre l’URL de redirection.

Un aller-retour est effectué avec le serveur quand une URL est redirigée.

Avertissement

Soyez prudent lors de l’établissement de règles de redirection. Les règles de redirection sont évaluées à chaque requête effectuée à l’application, notamment après une redirection. Il est facile de créer accidentellement une boucle de redirections infinies.

Requête d’origine : /redirect-rule/1234/5678

Add redirect: Browser window with developer tools tracking the requests and responses

La partie de l’expression entre parenthèses est appelée groupe de capture. Le point (.) de l’expression signifie mettre en correspondance n’importe quel caractère. L’astérisque (*) indique mettre en correspondance zéro occurrence ou plus du caractère précédent. Par conséquent, les deux derniers segments de chemin de l’URL, 1234/5678, sont capturés par le groupe de capture (.*). Toute valeur fournie dans l’URL de la requête après redirect-rule/ est capturée par ce groupe de capture unique.

Dans la chaîne de remplacement, les groupes capturés sont injectés dans la chaîne avec le signe dollar ($) suivi du numéro de séquence de la capture. La valeur du premier groupe de capture est obtenue avec $1, la deuxième avec $2, et ainsi de suite en séquence pour les groupes de capture de votre expression régulière. Comme il n’y a qu’un seul groupe capturé dans l’expression régulière de la règle de redirection de l’exemple d’application, un seul groupe est injecté dans la chaîne de remplacement, à savoir $1. Quand la règle est appliquée, l’URL devient /redirected/1234/5678.

Redirection d’URL vers un point de terminaison sécurisé

Utilisez AddRedirectToHttps pour rediriger les requêtes HTTP vers le même hôte et le même chemin avec le protocole HTTPS. Si le code d’état n’est pas fourni, le middleware utilise par défaut 302 - Trouvé. Si le port n’est pas fourni :

  • Le middleware utilise par défaut null.
  • Le schéma change en https (protocole HTTPS), et le client accède à la ressource sur le port 443.

L’exemple suivant montre comment définir le code d’état sur 301 - Moved Permanently et changer le port en 5001.

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttps(301, 5001);

    app.UseRewriter(options);
}

Utilisez AddRedirectToHttpsPermanent pour rediriger les requêtes non sécurisées vers le même hôte et le même chemin avec le protocole HTTPS sécurisé sur le port 443. L’intergiciel définit le code d’état sur 301 - Moved Permanently.

public void Configure(IApplicationBuilder app)
{
    var options = new RewriteOptions()
        .AddRedirectToHttpsPermanent();

    app.UseRewriter(options);
}

Remarque

Si vous effectuez une redirection vers un point de terminaison sécurisé et que vous n’avez pas besoin de règles de redirection supplémentaires, nous vous recommandons d’utiliser le middleware de redirection HTTPS. Pour plus d’informations, consultez la rubrique Appliquer HTTPS.

L’exemple d’application peut montrer comment utiliser AddRedirectToHttps ou AddRedirectToHttpsPermanent. Ajoutez la méthode d’extension à RewriteOptions. Effectuez une requête non sécurisée à l’application à n’importe quelle URL. Ignorez l’avertissement de sécurité du navigateur indiquant que le certificat auto-signé n’est pas approuvé ou créez une exception pour approuver le certificat.

Requête d’origine utilisant AddRedirectToHttps(301, 5001) : http://localhost:5000/secure

Add redirect to HTTPS: Browser window with developer tools tracking the requests and responses

Requête d’origine utilisant AddRedirectToHttpsPermanent : http://localhost:5000/secure

Add redirect to HTTPS permanent: Browser window with developer tools tracking the requests and responses

Réécrire URL

Utilisez AddRewrite pour créer une règle pour la réécriture d’URL. Le premier paramètre contient l’expression régulière pour la mise en correspondance sur le chemin de l’URL entrante. Le deuxième paramètre est la chaîne de remplacement. Le troisième paramètre, skipRemainingRules: {true|false}, indique à l’intergiciel d’ignorer, ou non, les règles de réécriture supplémentaires si la règle actuelle est appliquée.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

Requête d’origine : /rewrite-rule/1234/5678

Add rewrite: Browser window with developer tools tracking the request and response

Le caret (^) au début de l’expression signifie que la correspondance commence au début du chemin de l’URL.

Dans l’exemple précédent avec la règle de redirection, redirect-rule/(.*), il n’existe pas de caret (^) au début de l’expression régulière. Ainsi, n’importe quel caractère peut précéder redirect-rule/ dans le chemin pour qu’une correspondance soit établie.

Chemin d’accès Correspond
/redirect-rule/1234/5678 Oui
/my-cool-redirect-rule/1234/5678 Oui
/anotherredirect-rule/1234/5678 Oui

La règle de réécriture, ^rewrite-rule/(\d+)/(\d+), établit une correspondance uniquement avec des chemins d’accès s’ils commencent par rewrite-rule/. Dans le tableau suivant, notez la différence de correspondance.

Chemin d’accès Correspond
/rewrite-rule/1234/5678 Oui
/my-cool-rewrite-rule/1234/5678 No
/anotherrewrite-rule/1234/5678 Non

À la suite de la partie ^rewrite-rule/ de l’expression se trouvent deux groupes de capture, (\d+)/(\d+). \d signifie établir une correspondance avec un chiffre (nombre). Le signe plus (+) signifie établir une correspondance avec une ou plusieurs occurrences du caractère précédent. Par conséquent, l’URL doit contenir un nombre suivi d’une barre oblique, elle-même suivie d’un autre nombre. Ces groupes sont injectés dans l’URL réécrite sous la forme $1 et $2. La chaîne de remplacement de la règle de réécriture place les groupes capturés dans la chaîne de requête. Le chemin demandé /rewrite-rule/1234/5678 est réécrit pour obtenir la ressource à l’emplacement /rewritten?var1=1234&var2=5678. Si une chaîne de requête est présente dans la requête d’origine, elle est conservée lors de la réécriture de l’URL.

Il n’y a pas d’aller-retour avec le serveur pour obtenir la ressource. Si la ressource existe, elle est récupérée et retournée au client avec le code d’état 200 - OK. Comme le client n’est pas redirigé, l’URL dans la barre d’adresse du navigateur ne change pas. Les clients ne peuvent pas détecter qu’une opération de réécriture d’URL s’est produite sur le serveur.

Remarque

Quand c’est possible, utilisez skipRemainingRules: true, car la mise en correspondance de règles est un processus gourmand en ressources qui augmente le temps de réponse de l’application. Pour obtenir la réponse d’application la plus rapide :

  • Classez vos règles de réécriture en partant de la règle la plus souvent mise en correspondance jusqu’à la règle la moins souvent mise en correspondance.
  • Ignorez le traitement des règles restantes quand une correspondance est trouvée et qu’aucun traitement de règle supplémentaire n’est nécessaire.

Apache mod_rewrite

Appliquez des règles Apache mod_rewrite avec AddApacheModRewrite. Vérifiez que le fichier de règles est déployé avec l’application. Pour obtenir plus d’informations et des exemples de règles mod_rewrite, consultez Apache mod_rewrite.

Un StreamReader est utilisé pour lire les règles dans le fichier de règles ApacheModRewrite.txt :

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

L’exemple d’application redirige les requêtes de /apache-mod-rules-redirect/(.\*) vers /redirected?id=$1. Le code d’état de la réponse est 302 - Trouvé.

# Rewrite path with additional sub directory
RewriteRule ^/apache-mod-rules-redirect/(.*) /redirected?id=$1 [L,R=302]

Requête d’origine : /apache-mod-rules-redirect/1234

Add Apache mod redirect: Browser window with developer tools tracking the requests and responses

L’intergiciel prend en charge les variables de serveur Apache mod_rewrite suivantes :

  • CONN_REMOTE_ADDR
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_FORWARDED
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_USER_AGENT
  • HTTPS
  • IPV6
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_METHOD
  • REQUEST_SCHEME
  • REQUEST_URI
  • SCRIPT_FILENAME
  • SERVER_ADDR
  • SERVER_PORT
  • SERVER_PROTOCOL
  • TEMPS
  • TIME_DAY
  • TIME_HOUR
  • TIME_MIN
  • TIME_MON
  • TIME_SEC
  • TIME_WDAY
  • TIME_YEAR

Règles du module de réécriture d’URL IIS

Pour utiliser le même ensemble de règles que celui qui s’applique au module de réécriture d’URL IIS, utilisez AddIISUrlRewrite. Vérifiez que le fichier de règles est déployé avec l’application. N’indiquez pas au middleware d’utiliser le fichier web.config de l’application en cas d’exécution sur Windows Server IIS. Avec IIS, ces règles doivent être stockées en dehors du fichier web.config de l’application pour éviter les conflits avec le module de réécriture IIS. Pour obtenir plus d’informations et des exemples de règles du module de réécriture d’URL IIS, consultez Utilisation du module de réécriture d’URL 2.0 et Informations de référence sur la configuration du module de réécriture d’URL.

Un StreamReader est utilisé pour lire les règles dans le fichier de règles IISUrlRewrite.xml :

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

L’exemple d’application réécrit les requêtes de /iis-rules-rewrite/(.*) vers /rewritten?id=$1. La réponse est envoyée au client avec le code d’état 200 - OK.

<rewrite>
  <rules>
    <rule name="Rewrite segment to id querystring" stopProcessing="true">
      <match url="^iis-rules-rewrite/(.*)$" />
      <action type="Rewrite" url="rewritten?id={R:1}" appendQueryString="false"/>
    </rule>
  </rules>
</rewrite>

Requête d’origine : /iis-rules-rewrite/1234

Add IIS URL rewrite: Browser window with developer tools tracking the request and response

Si vous avez un module de réécriture IIS actif pour lequel des règles au niveau du serveur qui affecteraient de façon non souhaitée votre application sont configurées, vous pouvez le désactiver pour une application. Pour plus d’informations, consultez Désactivation de modules IIS.

Fonctionnalités non prises en charge

L’intergiciel intégré à ASP.NET Core 2.x ne prend pas en charge les fonctionnalités de module de réécriture d’URL IIS suivantes :

  • Règles de trafic sortant
  • Variables serveur personnalisées
  • Caractères génériques
  • LogRewrittenUrl

Variables de serveur prises en charge

L’intergiciel prend en charge les variables serveur du module de réécriture d’URL IIS suivantes :

  • CONTENT_LENGTH
  • CONTENT_TYPE
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_URL
  • HTTP_USER_AGENT
  • HTTPS
  • LOCAL_ADDR
  • QUERY_STRING
  • REMOTE_ADDR
  • REMOTE_PORT
  • REQUEST_FILENAME
  • REQUEST_URI

Remarque

Vous pouvez également obtenir un IFileProvider par le biais d’un PhysicalFileProvider. Cette approche peut fournir davantage de flexibilité pour l’emplacement de vos fichiers de règles de réécriture. Vérifiez que vos fichiers de règles de réécriture sont déployés sur le serveur dans le chemin que vous fournissez.

PhysicalFileProvider fileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());

Règle basée sur une méthode

Utilisez Add pour implémenter votre propre logique de règle dans une méthode. Add expose RewriteContext, ce qui rend HttpContext disponible pour une utilisation dans votre méthode. RewriteContext.Result détermine la façon dont le traitement du pipeline supplémentaire est géré. Définissez la valeur sur un des champs RuleResult décrits dans le tableau suivant.

Réécrire le résultat du contexte Action
RuleResult.ContinueRules (valeur par défaut) Continuer à appliquer les règles.
RuleResult.EndResponse Cesser d’appliquer les règles et envoyer la réponse.
RuleResult.SkipRemainingRules Cesser d’appliquer les règles et envoyer le contexte au middleware suivant.
public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

L’exemple d’application présente une méthode qui redirige les requêtes de chemins qui se terminent par .xml. Si une requête est faite pour /file.xml, la requête est redirigée vers /xmlfiles/file.xml. Le code d’état est défini sur 301 - Moved Permanently. Quand le navigateur fait une nouvelle requête pour /xmlfiles/file.xml, l’intergiciel de fichiers statiques délivre le fichier au client à partir du dossier wwwroot/xmlfiles. Pour une redirection, définissez explicitement le code d’état de la réponse. Sinon, un code d’état 200 - OK est retourné et la redirection ne se produit pas sur le client.

RewriteRules.cs :

public static void RedirectXmlFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    // Because the client is redirecting back to the same app, stop 
    // processing if the request has already been redirected.
    if (request.Path.StartsWithSegments(new PathString("/xmlfiles")))
    {
        return;
    }

    if (request.Path.Value.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
    {
        var response = context.HttpContext.Response;
        response.StatusCode = (int) HttpStatusCode.MovedPermanently;
        context.Result = RuleResult.EndResponse;
        response.Headers[HeaderNames.Location] = 
            "/xmlfiles" + request.Path + request.QueryString;
    }
}

Cette approche peut également réécrire des requêtes. L’exemple d’application montre la réécriture du chemin pour toute requête demandant de délivrer le fichier texte file.txt à partir du dossier wwwroot. Le middleware de fichiers statiques délivre le fichier en fonction du chemin de requête mis à jour :

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

RewriteRules.cs :

public static void RewriteTextFileRequests(RewriteContext context)
{
    var request = context.HttpContext.Request;

    if (request.Path.Value.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
    {
        context.Result = RuleResult.SkipRemainingRules;
        request.Path = "/file.txt";
    }
}

Règle basée sur IRule

Utilisez Add pour insérer votre propre logique de règle dans une classe qui implémente l’interface IRule. IRule offre davantage de flexibilité par rapport à l’approche de la règle basée sur une méthode. Votre classe d’implémentation peut inclure un constructeur qui vous permet de passer des paramètres pour la méthode ApplyRule.

public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

    app.Run(context => context.Response.WriteAsync(
        $"Rewritten or Redirected Url: " +
        $"{context.Request.Path + context.Request.QueryString}"));
}

Les valeurs des paramètres dans l’exemple d’application pour extension et newPath sont vérifiées afin de remplir plusieurs conditions. extension doit contenir une valeur, laquelle doit être .png, .jpg ou .gif. Si newPath n’est pas valide, un ArgumentException est levé. Si une requête est faite pour image.png, la requête est redirigée vers /png-images/image.png. Si une requête est faite pour image.jpg, la requête est redirigée vers /jpg-images/image.jpg. Le code d’état est défini sur 301 - Moved Permanently, et context.Result est défini de façon à cesser le traitement des règles et envoyer la réponse.

public class RedirectImageRequests : IRule
{
    private readonly string _extension;
    private readonly PathString _newPath;

    public RedirectImageRequests(string extension, string newPath)
    {
        if (string.IsNullOrEmpty(extension))
        {
            throw new ArgumentException(nameof(extension));
        }

        if (!Regex.IsMatch(extension, @"^\.(png|jpg|gif)$"))
        {
            throw new ArgumentException("Invalid extension", nameof(extension));
        }

        if (!Regex.IsMatch(newPath, @"(/[A-Za-z0-9]+)+?"))
        {
            throw new ArgumentException("Invalid path", nameof(newPath));
        }

        _extension = extension;
        _newPath = new PathString(newPath);
    }

    public void ApplyRule(RewriteContext context)
    {
        var request = context.HttpContext.Request;

        // Because we're redirecting back to the same app, stop 
        // processing if the request has already been redirected
        if (request.Path.StartsWithSegments(new PathString(_newPath)))
        {
            return;
        }

        if (request.Path.Value.EndsWith(_extension, StringComparison.OrdinalIgnoreCase))
        {
            var response = context.HttpContext.Response;
            response.StatusCode = (int) HttpStatusCode.MovedPermanently;
            context.Result = RuleResult.EndResponse;
            response.Headers[HeaderNames.Location] = 
                _newPath + request.Path + request.QueryString;
        }
    }
}

Requête d’origine : /image.png

For image.png: Browser window with developer tools tracking the requests and responses

Requête d’origine : /image.jpg

For image.jpg: Browser window with developer tools tracking the requests and responses

Exemples d’expressions régulières

Objectif Chaîne d’expression régulière et
exemple de correspondance
Chaîne de remplacement et
Exemple de sortie
Réécrire le chemin dans la chaîne de requête ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Supprimer la barre oblique finale (.*)/$
/path/
$1
/path
Appliquer une barre oblique finale (.*[^/])$
/path
$1/
/path/
Éviter la réécriture des requêtes spécifiques ^(.*)(?<!\.axd)$ ou ^(?!.*\.axd$)(.*)$
Oui : /resource.htm
Non : /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Réorganiser les segments d’URL path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Remplacer un segment d’URL ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

Ressources supplémentaires