URL-umschreibende Middleware in ASP.NET Core

Von Kirk Larkin und Rick Anderson

In diesem Artikel wird das Neuschreiben von URLs beschrieben. Außerdem erhalten Sie Anweisungen zur Verwendung von Middleware zum Neuschreiben von URLs in ASP.NET Core-Apps.

Bei der URL-Umschreibung werden die Anforderungs-URLs verändert, die auf mindesten einer vordefinierten Regel basieren. Es wird eine Abstraktion zwischen den Speicherorten und Adressen von Ressourcen erstellt, sodass diese nicht eng miteinander verknüpft sind. Die URL-Neuschreibung ist hilfreich in verschiedenen Szenarios wie:

  • Kurzzeitiges oder permanentes Verschieben oder Ersetzen von Serverressourcen, sowie Erhalten von stabilen Locators für diese Ressourcen.
  • Verteilen der Verarbeitung von Anforderungen auf verschiedene Apps oder Bereiche einer App.
  • Entfernen, Hinzufügen oder Umorganisieren von URL-Segmenten bei eingehenden Anforderungen.
  • Optimieren von öffentlichen URLs für die Suchmaschinenoptimierung (Search Engine Optimization, SEO).
  • Gestatten der Verwendung von angezeigten öffentlichen URLs, um Besuchern zu helfen, den Inhalt vorherzusagen, der durch die Anforderung einer Ressource zurückgegeben wird.
  • Umleiten von unsicheren Anforderungen auf sichere Endpunkte.
  • Verhindern von Hotlinks zu externen Websites, die eine gehostete statische Ressource auf einer anderen Website verwenden, bei der die Ressource zu ihrem eigenen Inhalt verlinkt wird.

Wenn Sie URLs neu schreiben, kann das negative Auswirkungen auf die Leistung einer App haben. Sie sollten so wenig Regeln wie möglich erstellen und darauf achten, dass diese nicht zu komplex sind.

Umleiten und Umschreiben von URLs

Der Unterschied zwischen dem Umleiten und Neu schreiben von URLs ist zwar gering, allerdings haben die beiden Verfahren sehr unterschiedliche Auswirkungen auf die Bereitstellung von Ressourcen für Clients. Die URL-umschreibenden Middleware von ASP.NET Core kann für beide Vorgänge verwendet werden.

Bei der Umleitung von URLs findet ein clientseitiger Vorgang statt, bei dem der Client angewiesen wird, auf eine Ressource unter einer anderen Adresse zuzugreifen, als die, die der Client ursprünglich angefordert hat. Dafür ist ein Roundtrip zum Server erforderlich. Die Umleitungs-URL, die an den Client zurückgegeben wird, wird in der Adressleiste des Browsers angezeigt, wenn der Client eine neue Anforderung an die Ressource sendet.

Wenn /resource auf /different-resourceumgeleitet wird, sendet der Server die Antwort, dass der Client die Ressource unter /different-resource abrufen soll. In der Antwort ist außerdem ein Statuscode enthalten, aus dem entnommen werden kann, ob die Umleitung temporär oder permanent ist.

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.

Wenn Anforderungen auf eine andere URL umgeleitet werden, muss angegeben werden, ob die Umleitung temporär oder permanent sein soll. Geben Sie hierzu den Statuscode mit der Antwort an:

  • Der Statuscode 301 - Moved Permanently wird verwendet, wenn der Ressource eine neue permanente URL zugewiesen wurde und alle zukünftigen Anforderungen an die Ressource die neue URL verwenden sollen. Der Client kann die Antwort zwischenspeichern und wiederverwenden, wenn der Statuscode 301 empfangen wird.

  • Der Statuscode 302 - Found wird verwendet, wenn die Umleitung temporär ist oder sowieso Änderungen vorbehalten sind. Der Statuscode 302 teilt dem Client mit, dass die URL nicht gespeichert und nicht wiederverwendet werden soll.

Weitere Informationen zu Statuscodes finden Sie unter RFC 2616: Status Code Definitions.

Bei der Neuschreibung einer URL handelt es sich um einen serverseitigen Vorgang, bei dem eine Ressource von einer anderen Ressourcenadresse, als der vom Client angeforderten, bereitgestellt wird. Wenn eine URL neu geschrieben wird, ist kein Roundtrip zum Server erforderlich. Die neu geschriebene URL wird nicht an den Server zurückgegeben und nicht in der Adressleiste des Browsers angezeigt.

Wenn /resource in /different-resourceumgeschrieben wird, ruft der Server die Ressource intern ab und gibt sie zurück an /different-resource.

Auch wenn der Client die Ressource unter der neu geschriebene URL abrufen kann, erhält er nicht die Information, dass die Ressource unter der umgeschriebenen URL gespeichert ist, wenn er die Anforderung sendet und eine Antwort erhält.

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.

URL-umschreibende Beispiel-App

Mit der Beispiel-App können Sie die Features der Middleware zum Neuschreiben von URLs testen. Die App wendet Umleitungs- und Neuschreibungsregeln an und zeigt die umgeleitete oder neu geschriebene URL für verschiedene Szenarios an. Die in Azure bereitgestellte Beispiel-App kann für Testzwecke verwendet werden.

Empfohlene Verwendung der Middleware zum Neuschreiben von URLs

Verwenden Sie Middleware zur URL-Neuschreibung, wenn die folgenden Ansätze nicht ausreichend sind:

Verwenden Sie die Middleware für URL-Neuschreibung, wenn die Anwendung auf dem HTTP.sys-Server gehostet wird.

Die Hauptgründe für die Verwendung der serverbasierten Technologien zur URL-Neuschreibung in IIS, Apache und Nginx sind:

  • Die Middleware unterstützt nicht alle Features dieser Module.

    Einige Features der Servermodule funktionieren nicht mit ASP.NET Core-Projekten – z.B. die Einschränkungen IsFile und IsDirectory des IIS-Neuschreibungsmoduls. Verwenden Sie in diesem Szenario stattdessen die Middleware.

  • Die Leistung der Middleware stimmt wahrscheinlich nicht mit der Leistung der Module überein.

    Benchmarking ist der einzige Weg, um sicher festzustellen, welcher Ansatz die Leistung am meisten beeinträchtigt oder ob die nachlassende Leistung nur geringfügig ist.

Erweiterung und Optionen

Legen Sie Regeln für URL-Neuschreibung und -Umleitung fest, indem Sie eine Instanz der RewriteOptions-Klasse erstellen und Erweiterungsmethoden für jede Neuschreibungsregel hinzufügen. Verketten Sie mehrere Regeln in der Reihenfolge, in der sie verarbeitet werden sollen. Die RewriteOptions werden an die Middleware zur URL-Neuschreibung übergeben, wenn diese mit UseRewriter zu der Anforderungspipeline hinzugefügt wird:

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

Umleitung einer Nicht-WWW-Anforderung an eine WWW-Anforderung

Drei Optionen ermöglichen der App, Nicht-www-Anforderungen an www umzuleiten:

  • AddRedirectToWwwPermanent: Die Anforderung wird dauerhaft an die Unterdomäne www umgeleitet, sofern die Anforderung nicht www ist. Wird mit dem Statuscode Status308PermanentRedirect umgeleitet.

  • AddRedirectToWww: Die Anforderung wird an die Unterdomäne www umgeleitet, sofern die eingehende Anforderung nicht www ist. Wird mit dem Statuscode Status307TemporaryRedirect umgeleitet. Eine Überladung ermöglicht es, den Statuscode für die Antwort zu senden. Verwenden Sie ein Feld der StatusCodes-Klasse, um einen Statuscode zuzuweisen.

Umleitungs-URL

Verwenden Sie AddRedirect, um Anforderungen umzuleiten. Der erste Parameter enthält den regulären .NET-Ausdruck (RegEx) für die Zuordnung zum Pfad der eingehenden URL. Beim zweiten Parameter handelt es sich um eine Ersatzzeichenfolge. Der dritte Parameter gibt, falls vorhanden, den Statuscode an. Wenn der Statuscode nicht angegeben wird, wird standardmäßig 302 – Gefunden zurückgegeben. Dies bedeutet, dass die Ressource vorübergehend verschoben oder ersetzt wurde.

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

Aktivieren Sie in Ihrem Browser die Entwicklertools, und senden Sie eine Anforderung an die Beispiel-App mit dem Pfad /redirect-rule/1234/5678. Der reguläre Ausdruck stimmt mit dem Anforderungspfad unter redirect-rule/(.*) überein, und der Pfad wird durch /redirected/1234/5678 ersetzt. Die Umleitungs-URL wird mit dem Statuscode 302 – Gefunden an den Client zurückgesendet. Unter der Umleitungs-URL sendet der Browser eine neue Anforderung, die in dessen Adressleiste angezeigt wird. Da keine Regel in der Beispiel-App mit der Umleitungs-URL übereinstimmt:

  • Die zweite Anforderung erhält die Antwort 200 – OK von der App.
  • Der Antworttext zeigt die Umleitungs-URL an.

Wenn eine URL weitergeleitet wird, wird ein Roundtrip zum Server ausgelöst.

Warnung

Seien Sie vorsichtig, wenn Sie Umleitungsregeln einrichten. Bei jeder Anforderung an die App werden Umleitungsregeln überprüft – auch nach einer Umleitung. Dabei kann schnell aus Versehen eine Dauerschleife von Umleitungen entstehen.

Der Teil des Ausdruck in Klammern wird als Erfassungsgruppe bezeichnet. Der Punkt (.) im Ausdruck steht für Übereinstimmung mit beliebigem Zeichen. Das Sternchen (*) steht für Übereinstimmung mit dem vorausgehenden Zeichen (keinmal oder mindestens einmal) . Daher werden die letzten beiden Pfadsegmente der URL (1234/5678) von der Erfassungsgruppe erfasst (.*). Alle Werte, die in der Anforderungs-URL nach redirect-rule/ angegeben werden, werden von dieser Erfassungsgruppe erfasst.

Erfassungsgruppen werden in der Ersetzungszeichenfolge mit dem Dollarzeichen ($) in die Zeichenfolge eingefügt. Danach folgt die Sequenznummer der Erfassung. Der erste Wert der Erfassungsgruppe wird mit $1 abgerufen, der zweite mit $2. Dies wird in Sequenzen für die Erfassungsgruppen im regulären Ausdruck weitergeführt. Es gibt nur eine erfasste Gruppe im regulären Ausdruck der Umleitungsregel in redirect-rule/(.*), also gibt es auch nur eine injizierte Gruppe in der Ersetzungszeichenfolge, nämlich $1. Wenn die Regel angewendet wird, ändert sich die URL in /redirected/1234/5678.

Versuchen Sie /redirect-rule/1234/5678 mit den Browsertools auf der Registerkarte „Netzwerk“.

URL-Umleitung an einen sicheren Endpunkt

Verwenden Sie AddRedirectToHttps, um HTTP-Anforderungen auf denselben Host und Pfad mithilfe des HTTPS-Protokolls umzuleiten. Wenn kein Statuscode angegeben wird, wird für die Middleware standardmäßig 302 – Gefunden zurückgegeben. Wenn kein Port angegeben ist:

  • Für die Middleware wird standardmäßig null zurückgegeben.
  • Das Schema ändert sich in https (HTTPS-Protokoll), und der Client hat über Port 443 Zugriff auf die Ressource.

Das folgende Beispiel zeigt, wie Sie den Statuscode auf 301 - Moved Permanently festlegen und den Port in den HTTPS-Port ändern, der von Kestrel auf localhost verwendet wird. In der Produktion ist der HTTPS-Port auf NULL festgelegt:

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

Verwenden Sie AddRedirectToHttpsPermanent, um unsichere Anforderungen auf denselben Host und Pfad mit einem sicheren HTTPS-Protokoll auf Port 443 umzuleiten. Die Middleware legt den Statuscode auf 301 - Moved Permanently fest.

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

Hinweis

Wenn Sie eine Umleitung an einen sicheren Endpunkt ohne weitere erforderliche Umleitungsregeln durchführen, wird empfohlen, Middleware für HTTPS-Umleitung zu verwenden. Weitere Informationen finden Sie unter Erzwingen von HTTPS.

Die Beispiel-App veranschaulicht, wie AddRedirectToHttps oder AddRedirectToHttpsPermanent verwendet wird. Senden Sie eine unsichere Anforderung an die App. Beim Testen der Umleitung von HTTP zu HTTPS mit localhost:

  • Verwenden Sie die HTTP-URL, die über einen anderen Port als die HTTPS-URL verfügt. Die HTTP-URL befindet sich in der Datei Properties/launchSettings.json.
  • Das Entfernen von s aus https://localhost/{port} schlägt fehl, da localhost dem HTTPS-Port nicht über HTTP antwortet.

Die folgende Abbildung zeigt die F12-Browsertools mit einer Anforderung an http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz mithilfe des Codes oben:

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

Umschreiben einer URL

Erstellen Sie mithilfe von AddRewrite eine Regel zum Umschreiben von URLs. Der erste Parameter enthält den regulären Ausdruck für die Zuordnung zum Pfad der eingehenden URL. Beim zweiten Parameter handelt es sich um eine Ersatzzeichenfolge. Der dritte Parameter (skipRemainingRules: {true|false}) teilt der Middleware mit, ob sie zusätzliche Umschreibungsregeln überspringen soll, wenn die aktuelle Regel angewendet wird.

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

Ausprobieren der Anforderung an https://redirect6.azurewebsites.net/rewrite-rule/1234/5678

Das Zirkumflexzeichen (^) am Anfang des Ausdrucks bedeutet, dass die Übereinstimmung schon am Anfang des URL-Pfads beginnt.

In dem vorherigen Beispiel zu den Umleitungsregeln, redirect-rule/(.*), beginnt der reguläre Ausdruck nicht mit einem Zirkumflexzeichen (^). So kann für eine Übereinstimmung ein beliebiges Zeichen im Pfad vor redirect-rule/ stehen.

Pfad Match
/redirect-rule/1234/5678 Ja
/my-cool-redirect-rule/1234/5678 Ja
/anotherredirect-rule/1234/5678 Ja

Die Umschreibungsregel (^rewrite-rule/(\d+)/(\d+)) stimmt nur mit Pfaden überein, wenn sie mit rewrite-rule/ beginnen. Beachten Sie die unterschiedliche Übereinstimmung in der folgenden Tabelle:

Pfad Match
/rewrite-rule/1234/5678 Ja
/my-cool-rewrite-rule/1234/5678 Nein
/anotherrewrite-rule/1234/5678 Nein

Auf den ^rewrite-rule/-Teil des Ausdruck folgen zwei Erfassungsgruppen: (\d+)/(\d+). \d steht für Übereinstimmung mit einer Ziffer (Zahl) . Das Pluszeichen (+) steht für match one or more of the preceding character (Übereinstimmung mit mindestens einem vorausgehenden Zeichen). Aus diesem Grund muss die URL eine Zahl enthalten, auf die ein Schrägstrich und eine weitere Zahl folgt. Die Erfassungsgruppen werden in die umgeschriebene URL als $1 und $2 eingefügt. Über die Ersetzungszeichenfolge der Neuschreibungsregel werden die Erfassungsgruppen in die Abfragezeichenfolge eingefügt. Der angeforderte /rewrite-rule/1234/5678-Pfad wird neu geschrieben, um die Ressource unter /rewritten?var1=1234&var2=5678 zurückzugeben. Wenn es in der ursprünglichen Anforderung eine Abfragezeichenfolge gibt, bleibt diese erhalten, wenn die URL umgeschrieben wird.

Es gibt keinen Roundtrip zum Server, um die Ressource zurückzugeben. Wenn es die Ressource gibt, wird sie abgerufen und dem Client mit dem Statuscode 200 – OK zurückgegeben. Da der Client nicht umgeleitet wird, ändert sich die URL in der Adressleiste des Browsers nicht. Clients können nicht erkennen, dass ein Vorgang zum erneuten Schreiben einer URL auf dem Server stattgefunden hat.

Leistungstipps zum Neuschreiben und Umleiten von URLs

Führen Sie folgende Schritte aus, um die schnellsten Antwortzeiten zu erreichen:

  • Sortieren Sie Neuschreibungsregeln von der am häufigsten abgeglichenen Regel zu der am seltensten abgeglichenen Regel.
  • Verwenden Sie skipRemainingRules: true, wo immer das möglich ist, da das Abgleichen von Regeln rechnerisch sehr aufwendig ist und die Antwortzeit der App erhöht. Überspringen Sie die Verarbeitung der übrigen Regeln, wenn es zu einer Übereinstimmung kommt und keine zusätzlichen Regelverarbeitungen erforderlich sind.

Warnung

Ein böswilliger Benutzer kann verarbeitungsintensive Eingaben für RegularExpressions angeben, um einen Denial-of-Service-Angriff durchzuführen. ASP.NET Core-Framework-APIs, die RegularExpressions verwenden, übergeben ein Timeout. Beispielsweise übergeben die RedirectRule- und RewriteRule-Klassen ein Timeout von einer Sekunde.

Apache: „mod_rewrite“

Wenden Sie die Apache-Regeln „mod_rewrite“ mit AddApacheModRewrite an. Vergewissern Sie sich, dass die Regeldatei mit der App bereitgestellt wird. Weitere Informationen zu diesen Regeln finden Sie unter Apache: „mod_rewrite“.

Zum Lesen der Regeldatei ApacheModRewrite.txt wird StreamReader verwendet:

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

Die Beispiel-App leitet Anforderungen von /apache-mod-rules-redirect/(.\*) auf /redirected?id=$1 um. Der Antwortstatuscode lautet 302 – Gefunden.

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

Ausprobieren der Anforderung an https://redirect6.azurewebsites.net/apache-mod-rules-redirect/1234

Die Apache-Middleware unterstützt die folgenden mod_rewrite-Servervariablen von Apache:

  • 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
  • TIME
  • TIME_DAY
  • TIME_HOUR
  • TIME_MIN
  • TIME_MON
  • TIME_SEC
  • TIME_WDAY
  • TIME_YEAR

Regeln zum IIS-Umschreibungsmodul

Um denselben Regelsatz zu verwenden, der für das IIS-Moduls für URL-Neuschreibung gilt, verwenden Sie AddIISUrlRewrite. Vergewissern Sie sich, dass die Regeldatei mit der App bereitgestellt wird. Geben Sie der Middleware nicht die Anweisung, die web.config-Datei der App zu verwenden, wenn sie auf der Windows Server-IIS ausgeführt wird. Bei IIS sollten diese Regeln außerhalb der web.config-Datei der App gespeichert werden, um Konflikte mit dem IIS-Neuschreibungsmodul zu vermeiden. Weitere Informationen und Beispiele zu den Regeln zum IIS-Umschreibungsmodul finden Sie unter Using Url Rewrite Module 2.0 (Verwenden des URL-Umschreibungsmoduls 2.0) und URL Rewrite Module Configuration Reference (Konfigurationsreferenz des URL-Umschreibungsmoduls).

Zum Lesen der Regeldatei IISUrlRewrite.xml wird StreamReader verwendet:

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

Die Beispiel-App schreibt Anforderungen von /iis-rules-rewrite/(.*) in /rewritten?id=$1 um. Die Antwort wird an den Client mit dem Statuscode 200 – OK gesendet.

<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>

Ausprobieren der Anforderung an https://redirect6.azurewebsites.net/iis-rules-rewrite/xyz

Für Apps, die über ein aktives IIS-Neuschreibungsmodul mit konfigurierten Regeln auf Serverebene verfügen, das die App in unerwünschter Weise beeinfluss, gilt Folgendes:

Nicht unterstützte Features

Die Middleware unterstützt die folgenden Features des IIS-URL-Umschreibungsmoduls nicht:

  • Ausgehende Regeln
  • Benutzerdefinierte Servervariablen
  • Platzhalter
  • LogRewrittenUrl

Unterstützte Servervariablen

Die Middleware unterstützt die folgenden Servervariablen für das IIS-URL-Neuschreibungsmodul:

  • 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

IFileProvider kann über einen PhysicalFileProvider abgerufen werden. Über diesen Ansatz können Sie flexibler einen Speicherort für die Dateien der Neuschreibungsregeln auswählen. Vergewissern Sie sich, dass die Dateien zu den Neuschreibungsregeln auf dem Server unter dem von Ihnen angegebenen Pfad bereitgestellt werden.

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

Methodenbasierte Regel

Verwenden Sie Add, um benutzerdefinierte Regellogik in einer Methode zu implementieren. Add macht RewriteContext verfügbar, wodurch die Verwendung von HttpContext in Umleitungsmethoden ermöglicht wird. Die RewriteContext.Result-Eigenschaft bestimmt, wie zusätzliche Pipelineverarbeitung erfolgt. Legen Sie den Wert auf eines der RuleResult-Felder fest, die in der folgenden Tabelle beschrieben sind:

Umschreiben von Kontext – Ergebnisse Aktion
RuleResult.ContinueRules (Standardwert) Regeln weiter anwenden.
RuleResult.EndResponse Regeln nicht mehr anwenden und Antwort senden.
RuleResult.SkipRemainingRules Regeln nicht mehr anwenden, und den Kontext an die nächste Middleware senden.
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();

In der Beispiel-App wird eine Methode dargestellt, die Anforderungen für Pfade weiterleitet, die auf .xml enden. Wenn eine Anforderung für /file.xml gesendet wird:

  • Die Anforderung wird an /xmlfiles/file.xml umgeleitet.
  • Der Statuscode wird auf 301 - Moved Permanently festgelegt. Wenn vom Browser eine neue Anforderung für /xmlfiles/file.xml gesendet wird, wird dem Client die Datei von Middleware für statische Dateien aus dem Ordner wwwroot/xmlfiles bereitgestellt. Legen Sie für eine Umleitung den Statuscode der Antwort explizit fest. Andernfalls wird ein Statuscode 200 – OK zurückgegeben, und die Umleitung findet nicht auf dem Client statt.

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

Bei diesem Ansatz können auch Anforderungen erneut generiert werden. In der Beispiel-App wird demonstriert, wie der Pfad für eine beliebige Textdateianforderung umgeschrieben wird, um die Textdatei file.txt aus dem Ordner wwwroot bereitzustellen. Middleware für statische Dateien stellt die Datei bereit, die auf dem aktualisierten Anforderungspfad basiert:

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

IRule-basierte Regel

Um Regellogik in einer Klasse zu nutzen, die die IRule-Schnittstelle implementiert, verwenden Sie Add. Wenn Sie IRule verwenden, können Sie flexibler entscheiden, ob Sie eine methodenbasierte Regel verwenden möchten. Die Implementierungsklasse kann einen Konstruktor enthalten, wodurch Parameter für die ApplyRule-Methode übergeben werden können.

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

Die Werte für die Parameter in der Beispiel-App für extension und newPath werden auf verschiedene Bedingungen geprüft. extension muss einen Wert enthalten, der .png, .jpg oder .gif entspricht. Wenn newPath nicht gültig ist, wird ArgumentException nicht ausgelöst. Wenn eine Anforderung für image.png erfolgt, wird sie zu /png-images/image.png umgeleitet. Wenn eine Anforderung für image.jpg erfolgt, wird sie zu /jpg-images/image.jpg umgeleitet. Der Statuscode wird auf 301 - Moved Permanently festgelegt, und context.Result erhält die Anweisung, Verarbeitungsregeln zu beenden und die Antwort zu senden.

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

Probieren Sie das:

RegEx-Beispiele

Ziel RegEx-Zeichenfolge &
übereinstimmendes Beispiel
Ersetzungszeichenfolge &
Ausgabebeispiel
Umschreiben des Pfads in die Abfragezeichenfolge ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Entfernen des nachgestellten Schrägstrichs ^path2/(.*)/$
/path2/xyz/
$1
/path2/xyz
Erzwingen des nachgestellten Schrägstrichs ^path3/(.*[^/])$
/path3/xyz
$1/
/path3/xyz/
Vermeiden des Umschreibens von bestimmten Anforderungen ^(.*)(?<!\.axd)$ oder
^(?!.*\.axd$)(.*)$
Ja: /path4/resource.htm
Nein: /path4/resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Ändern der Anordnung von URL-Segmenten path5/(.*)/(.*)/(.*)
path5/1/2/3
path5/$3/$2/$1
path5/3/2/1
Ersetzen von URL-Segmenten ^path6/(.*)/segment2/(.*)
^path6/segment1/segment2/segment3
path6/$1/replaced/$2
/path6/segment1/replaced/segment3

Die Links in der Tabelle oben verwenden den folgenden Code, der in Azure bereitgestellt wird:

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

In den meisten vorherigen Beispielen für reguläre Ausdrücke wird das Literal path verwendet, um eindeutige testbare Neuschreibungsregeln für das bereitgestellte Beispiel zu erstellen. In der Regel würde der reguläre Ausdruck path nicht enthalten. Sehen Sie sich beispielsweise diese Tabelle mit Beispielen für reguläre Ausdrücke an.

In diesem Artikel wird das Umschreiben von URLs beschrieben. Außerdem erhalten Sie Anweisungen zur Verwendung der URL-umschreibenden Middleware in ASP.NET Core-Apps.

Bei der URL-Umschreibung werden die Anforderungs-URLs verändert, die auf mindesten einer vordefinierten Regel basieren. Es wird eine Abstraktion zwischen den Speicherorten und Adressen von Ressourcen erstellt, sodass diese nicht eng miteinander verknüpft sind. Die URL-Neuschreibung ist hilfreich in verschiedenen Szenarios wie:

  • Kurzzeitiges oder permanentes Verschieben oder Ersetzen von Serverressourcen, sowie Erhalten von stabilen Locators für diese Ressourcen.
  • Verteilen der Verarbeitung von Anforderungen auf verschiedene Apps oder Bereiche einer App.
  • Entfernen, Hinzufügen oder Umorganisieren von URL-Segmenten bei eingehenden Anforderungen.
  • Optimieren von öffentlichen URLs für die Suchmaschinenoptimierung (Search Engine Optimization, SEO).
  • Gestatten der Verwendung von angezeigten öffentlichen URLs, um Besuchern zu helfen, den Inhalt vorherzusagen, der durch die Anforderung einer Ressource zurückgegeben wird.
  • Umleiten von unsicheren Anforderungen auf sichere Endpunkte.
  • Verhindern von Hotlinks zu externen Websites, die eine gehostete statische Ressource auf einer anderen Website verwenden, bei der die Ressource zu ihrem eigenen Inhalt verlinkt wird.

Hinweis

Wenn Sie URLs umschreiben, kann das negative Auswirkungen auf die Leistung einer App haben. Wenn möglich, sollten Sie so wenig Regeln wie möglich erstellen und darauf achten, dass diese nicht zu kompliziert sind.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Umleiten und Umschreiben von URLs

Der Unterschied zwischen dem Umleiten und Neu schreiben von URLs ist zwar gering, allerdings haben die beiden Verfahren sehr unterschiedliche Auswirkungen auf die Bereitstellung von Ressourcen für Clients. Die URL-umschreibenden Middleware von ASP.NET Core kann für beide Vorgänge verwendet werden.

Bei der Umleitung von URLs findet ein clientseitiger Vorgang statt, bei dem der Client angewiesen wird, auf eine Ressource unter einer anderen Adresse zuzugreifen, als die, die der Client ursprünglich angefordert hat. Dafür ist ein Roundtrip zum Server erforderlich. Die Umleitungs-URL, die an den Client zurückgegeben wird, wird in der Adressleiste des Browsers angezeigt, wenn der Client eine neue Anforderung an die Ressource sendet.

Wenn /resource auf /different-resourceumgeleitet wird, sendet der Server die Antwort, dass der Client die Ressource unter /different-resource abrufen soll. In der Antwort ist außerdem ein Statuscode enthalten, aus dem entnommen werden kann, ob die Umleitung temporär oder permanent ist.

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.

Wenn Anforderungen auf eine andere URL umgeleitet werden, muss angegeben werden, ob die Umleitung temporär oder permanent sein soll. Geben Sie hierzu den Statuscode mit der Antwort an:

  • Der Statuscode 301 - Moved Permanently wird verwendet, wenn der Ressource eine neue permanente URL zugewiesen wurde, und Sie dem Client die Anweisung geben möchten, dass alle zukünftigen Anforderungen an die Ressource die neue URL verwenden sollen. Der Client kann die Antwort zwischenspeichern und wiederverwenden, wenn der Statuscode 301 empfangen wird.

  • Der Statuscode 302 – Gefunden wird verwendet, wenn die Umleitung temporär ist oder sowieso Änderungen vorbehalten sind. Der Statuscode 302 teilt dem Client mit, dass die URL nicht gespeichert und nicht wiederverwendet werden soll.

Weitere Informationen zu Statuscodes finden Sie unter RFC 2616: Status Code Definitions.

Bei der Neuschreibung einer URL handelt es sich um einen serverseitigen Vorgang, bei dem eine Ressource von einer anderen Ressourcenadresse, als der vom Client angeforderten, bereitgestellt wird. Wenn eine URL neu geschrieben wird, ist kein Roundtrip zum Server erforderlich. Die neu geschriebene URL wird nicht an den Server zurückgegeben und nicht in der Adressleiste des Browsers angezeigt.

Wenn /resource in /different-resourceumgeschrieben wird, ruft der Server die Ressource intern ab und gibt sie zurück an /different-resource.

Auch wenn der Client die Ressource unter der neu geschriebene URL abrufen kann, erhält er nicht die Information, dass die Ressource unter der umgeschriebenen URL gespeichert ist, wenn er die Anforderung sendet und eine Antwort erhält.

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.

URL-umschreibende Beispiel-App

Mit der Beispiel-App können Sie die Features der Middleware zur URL-Neuschreibung testen. Die App wendet Umleitungs- und Neuschreibungsregeln an und zeigt die umgeleitete oder neu geschriebene URL für verschiedene Szenarios an.

Empfohlene Verwendung der Middleware zum Neuschreiben von URLs

Sie können Middleware zur URL-Neuschreibung verwenden, wenn die folgenden Ansätze nicht möglich sind:

Verwenden Sie die Middleware für URL-Neuschreibung, wenn die Anwendung auf dem HTTP.sys-Server gehostet wird.

Die Hauptgründe für die Verwendung der serverbasierten Technologien zur URL-Neuschreibung in IIS, Apache und Nginx sind:

  • Die Middleware unterstützt nicht alle Features dieser Module.

    Einige Features der Servermodule funktionieren nicht mit ASP.NET Core-Projekten – z.B. die Einschränkungen IsFile und IsDirectory des IIS-Neuschreibungsmoduls. Verwenden Sie in diesem Szenario stattdessen die Middleware.

  • Die Leistung der Middleware stimmt wahrscheinlich nicht mit der Leistung der Module überein.

    Benchmarking ist der einzige Weg, um sicher festzustellen, welcher Ansatz die Leistung am meisten beeinträchtigt oder ob die nachlassende Leistung nur geringfügig ist.

Package

Die URL-umschreibende Middleware wird über das Microsoft.AspNetCore.Rewrite-Paket bereitgestellt, das implizit in ASP.NET Core-Apps enthalten ist.

Erweiterung und Optionen

Legen Sie URL-Neuschreibungs- und -Umleitungsregeln fest, indem Sie eine Instanz der RewriteOptions-Klasse erstellen und Erweiterungsmethoden für jede Neuschreibungsregel hinzufügen. Verketten Sie mehrere Regeln in der Reihenfolge miteinander, in der sie verarbeitet werden sollen. Die RewriteOptions werden an die Middleware zur URL-Neuschreibung übergeben, wenn diese mit UseRewriter zu der Anforderungspipeline hinzugefügt wird:

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

Umleitung einer Nicht-WWW-Anforderung an eine WWW-Anforderung

Drei Optionen ermöglichen der App, Nicht-www-Anforderungen an www umzuleiten:

  • AddRedirectToWwwPermanent: Die Anforderung wird dauerhaft an die Unterdomäne www umgeleitet, sofern die Anforderung nicht www ist. Wird mit dem Statuscode Status308PermanentRedirect umgeleitet.

  • AddRedirectToWww: Die Anforderung wird an die Unterdomäne www umgeleitet, sofern die eingehende Anforderung nicht www ist. Wird mit dem Statuscode Status307TemporaryRedirect umgeleitet. Eine Überladung ermöglicht es Ihnen, den Statuscode für die Antwort zu senden. Verwenden Sie ein Feld der StatusCodes-Klasse, um einen Statuscode zuzuweisen.

Umleitungs-URL

Verwenden Sie AddRedirect, um Anforderungen umzuleiten. Der erste Parameter enthält Ihren regulären Ausdruck, damit dieser dem Pfad der eingehenden URL zugeordnet werden kann. Beim zweiten Parameter handelt es sich um eine Ersatzzeichenfolge. Der dritte Parameter gibt, falls vorhanden, den Statuscode an. Wenn Sie den Statuscode nicht angeben, wird standardmäßig 302 – Gefunden zurückgegeben, was bedeutet, dass die Ressource kurzzeitig verschoben oder ersetzt wurde.

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

Aktivieren Sie in Ihrem Browser die Entwicklertools, und senden Sie eine Anforderung an die Beispiel-App mit dem Pfad /redirect-rule/1234/5678. Der RegEx stimmt mit dem Anforderungspfad unter redirect-rule/(.*) überein, und der Pfad wird durch /redirected/1234/5678 ersetzt. Die Umleitungs-URL wird mit dem Statuscode 302 – Gefunden an den Client zurückgesendet. Unter der Umleitungs-URL sendet der Browser eine neue Anforderung, die in dessen Adressleiste angezeigt wird. Da keine Regel in der Beispiel-App mit der Umleitungs-URL übereinstimmt:

  • Die zweite Anforderung erhält die Antwort 200 – OK von der App.
  • Der Antworttext zeigt die Umleitungs-URL an.

Wenn eine URL weitergeleitet wird, wird ein Roundtrip zum Server ausgelöst.

Warnung

Seien Sie vorsichtig, wenn Sie Umleitungsregeln einrichten. Bei jeder Anforderung an die App werden Umleitungsregeln überprüft – auch nach einer Umleitung. Dabei kann schnell aus Versehen eine Dauerschleife von Umleitungen entstehen.

Ursprüngliche Anforderung: /redirect-rule/1234/5678

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

Der Teil des Ausdruck in Klammern wird als Erfassungsgruppe bezeichnet. Der Punkt (.) im Ausdruck steht für Übereinstimmung mit beliebigem Zeichen. Das Sternchen (*) steht für Übereinstimmung mit dem vorausgehenden Zeichen (keinmal oder mindestens einmal) . Daher werden die letzten beiden Pfadsegmente der URL (1234/5678) von der Erfassungsgruppe erfasst (.*). Alle Werte, die Sie in der Anforderungs-URL nach redirect-rule/ angeben, werden von dieser Erfassungsgruppe erfasst.

Erfassungsgruppen werden in der Ersetzungszeichenfolge mit dem Dollarzeichen ($) in die Zeichenfolge eingefügt. Danach folgt die Sequenznummer der Erfassung. Der erste Wert der Erfassungsgruppe wird mit $1 abgerufen, der zweite mit $2. Dies wird in Sequenzen für die Erfassungsgruppen Ihres RegEx weitergeführt. Nur eine Erfassungsgruppe ist in der Beispiel-App im RegEx der Umleitungsregel enthalten. Das bedeutet, dass es in die Ersetzungszeichenfolge nur eine Gruppe eingefügt wird, nämlich $1. Wenn die Regel angewendet wird, ändert sich die URL in /redirected/1234/5678.

URL-Umleitung an einen sicheren Endpunkt

Verwenden Sie AddRedirectToHttps, um HTTP-Anforderungen auf denselben Host und Pfad mithilfe des HTTPS-Protokolls umzuleiten. Wenn kein Statuscode angegeben wird, wird für die Middleware standardmäßig 302 – Gefunden zurückgegeben. Wenn kein Port angegeben ist:

  • Für die Middleware wird standardmäßig null zurückgegeben.
  • Das Schema ändert sich in https (HTTPS-Protokoll), und der Client hat über Port 443 Zugriff auf die Ressource.

Im folgenden Beispiel wird dargestellt, wie Sie den Statuscode 301 - Moved Permanently festlegen und den Port in 5001 ändern.

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

    app.UseRewriter(options);
}

Verwenden Sie AddRedirectToHttpsPermanent, um unsichere Anforderungen auf denselben Host und Pfad mit einem sicheren HTTPS-Protokoll auf Port 443 umzuleiten. Die Middleware legt den Statuscode auf 301 - Moved Permanently fest.

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

    app.UseRewriter(options);
}

Hinweis

Wenn Sie eine Umleitung an einen sicheren Endpunkt ohne weitere erforderliche Umleitungsregeln durchführen, wird empfohlen, Middleware für HTTPS-Umleitung zu verwenden. Weitere Informationen finden Sie im Artikel zum Erzwingen von HTTPS.

Anhand der Beispiel-App wird veranschaulicht, wie AddRedirectToHttps oder AddRedirectToHttpsPermanent verwendet werden sollen. Fügen Sie die Erweiterungsmethode zu den RewriteOptions hinzu. Senden Sie eine unsichere Anforderung an die App unter einer beliebigen URL. Schließen Sie die Sicherheitswarnung des Browsers, in der Sie darüber informiert werden, dass das selbstsignierte Zertifikat nicht vertrauenswürdig ist, oder erstellen sie eine Ausnahme, um dem Zertifikat zu vertrauen.

Ursprüngliche Anforderung über AddRedirectToHttps(301, 5001): http://localhost:5000/secure

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

Ursprüngliche Anforderung über AddRedirectToHttpsPermanent: http://localhost:5000/secure

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

Umschreiben einer URL

Erstellen Sie mithilfe von AddRewrite eine Regel zum Umschreiben von URLs. Der erste Parameter enthält den RegEx, damit dieser der eingehenden URL zugeordnet werden kann. Beim zweiten Parameter handelt es sich um eine Ersatzzeichenfolge. Der dritte Parameter (skipRemainingRules: {true|false}) teilt der Middleware mit, ob sie zusätzliche Umschreibungsregeln überspringen soll, wenn die aktuelle Regel angewendet wird.

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

Ursprüngliche Anforderung: /rewrite-rule/1234/5678

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

Das Zirkumflexzeichen (^) am Anfang des Ausdrucks bedeutet, dass die Übereinstimmung schon am Anfang des URL-Pfads beginnt.

In dem vorherigen Beispiel zu den Umleitungsregeln, redirect-rule/(.*), beginnt der RegEx nicht mit einem Zirkumflexzeichen (^). So kann für eine Übereinstimmung ein beliebiges Zeichen im Pfad vor redirect-rule/ stehen.

Pfad Match
/redirect-rule/1234/5678 Ja
/my-cool-redirect-rule/1234/5678 Ja
/anotherredirect-rule/1234/5678 Ja

Die Umschreibungsregel (^rewrite-rule/(\d+)/(\d+)) stimmt nur mit Pfaden überein, wenn sie mit rewrite-rule/ beginnen. Beachten Sie die unterschiedliche Übereinstimmung in der folgenden Tabelle:

Pfad Match
/rewrite-rule/1234/5678 Ja
/my-cool-rewrite-rule/1234/5678 Nein
/anotherrewrite-rule/1234/5678 Nein

Auf den ^rewrite-rule/-Teil des Ausdruck folgen zwei Erfassungsgruppen: (\d+)/(\d+). \d steht für Übereinstimmung mit einer Ziffer (Zahl) . Das Pluszeichen (+) steht für match one or more of the preceding character (Übereinstimmung mit mindestens einem vorausgehenden Zeichen). Aus diesem Grund muss die URL eine Zahl enthalten, auf die ein Schrägstrich und eine weitere Zahl folgt. Die Erfassungsgruppen werden in die umgeschriebene URL als $1 und $2 eingefügt. Über die Ersetzungszeichenfolge der Neuschreibungsregel werden die Erfassungsgruppen in die Abfragezeichenfolge eingefügt. Der angeforderte /rewrite-rule/1234/5678-Pfad wird umgeschrieben, um eine Ressource unter /rewritten?var1=1234&var2=5678 abzurufen. Wenn es in der ursprünglichen Anforderung eine Abfragezeichenfolge gibt, bleibt diese erhalten, wenn die URL umgeschrieben wird.

Es gibt keinen Roundtrip zum Server, um die Ressource abzurufen. Wenn es die Ressource gibt, wird sie abgerufen und dem Client mit dem Statuscode 200 – OK zurückgegeben. Da der Client nicht umgeleitet wird, ändert sich die URL in der Adressleiste des Browsers nicht. Clients können nicht erkennen, dass ein Vorgang zum erneuten Schreiben einer URL auf dem Server stattgefunden hat.

Hinweis

Verwenden Sie skipRemainingRules: true, wo immer das möglich ist, da das Abgleichen von Regeln rechnerisch sehr aufwendig ist und die Antwortzeit der App erhöht. Führen Sie folgende Schritte aus, um die schnellsten App-Antwortzeiten zu erreichen:

  • Sortieren Sie Neuschreibungsregeln von der am häufigsten abgeglichenen Regel zu der am seltensten abgeglichenen Regel.
  • Überspringen Sie die Verarbeitung der übrigen Regeln, wenn es zu einer Übereinstimmung kommt und keine zusätzlichen Regelverarbeitungen erforderlich sind.

Apache: „mod_rewrite“

Wenden Sie die Apache-Regeln „mod_rewrite“ mit AddApacheModRewrite an. Vergewissern Sie sich, dass die Regeldatei mit der App bereitgestellt wird. Weitere Informationen zu diesen Regeln finden Sie unter Apache: „mod_rewrite“.

Zum Lesen der Regeldatei ApacheModRewrite.txt wird StreamReader verwendet:

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

Die Beispiel-App leitet Anforderungen von /apache-mod-rules-redirect/(.\*) auf /redirected?id=$1 um. Der Antwortstatuscode lautet 302 – Gefunden.

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

Ursprüngliche Anforderung: /apache-mod-rules-redirect/1234

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

Die Middleware unterstützt die folgenden Servervariablen für die Apache „mod_rewrite“:

  • 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
  • TIME
  • TIME_DAY
  • TIME_HOUR
  • TIME_MIN
  • TIME_MON
  • TIME_SEC
  • TIME_WDAY
  • TIME_YEAR

Regeln zum IIS-Umschreibungsmodul

Um denselben Regelsatz zu verwenden, der für das IIS-Moduls für URL-Neuschreibung gilt, verwenden Sie AddIISUrlRewrite. Vergewissern Sie sich, dass die Regeldatei mit der App bereitgestellt wird. Geben Sie der Middleware nicht die Anweisung, die web.config-Datei der App zu verwenden, wenn sie auf der Windows Server-IIS ausgeführt wird. Bei IIS sollten diese Regeln außerhalb der web.config-Datei der App gespeichert werden, um Konflikte mit dem IIS-Neuschreibungsmodul zu vermeiden. Weitere Informationen und Beispiele zu den Regeln zum IIS-Umschreibungsmodul finden Sie unter Using Url Rewrite Module 2.0 (Verwenden des URL-Umschreibungsmoduls 2.0) und URL Rewrite Module Configuration Reference (Konfigurationsreferenz des URL-Umschreibungsmoduls).

Zum Lesen der Regeldatei IISUrlRewrite.xml wird StreamReader verwendet:

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

Die Beispiel-App schreibt Anforderungen von /iis-rules-rewrite/(.*) in /rewritten?id=$1 um. Die Antwort wird an den Client mit dem Statuscode 200 – OK gesendet.

<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>

Ursprüngliche Anforderung: /iis-rules-rewrite/1234

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

Wenn Sie über ein aktives IIS-Umschreibungsmodul verfügen, für das die Regeln auf Serverebene konfiguriert sind, die negative Auswirkungen auf Ihre App hätten, können Sie das IIS-Umschreibungsmodul für die App deaktivieren. Weitere Informationen finden Sie unter Disabling IIS modules (Deaktivieren von IIS-Modulen).

Nicht unterstützte Features

Die Middleware unterstützt die folgenden Features des IIS-URL-Umschreibungsmoduls nicht:

  • Ausgehende Regeln
  • Benutzerdefinierte Servervariablen
  • Platzhalter
  • LogRewrittenUrl

Unterstützte Servervariablen

Die Middleware unterstützt die folgenden Servervariablen für das IIS-URL-Umschreibungsmodul:

  • 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

Hinweis

Sie können IFileProvider auch über PhysicalFileProvider abrufen. Über diesen Ansatz können Sie flexibler einen Speicherort für die Dateien der Umschreibungsregeln auswählen. Vergewissern Sie sich, dass die Dateien zu den Umschreibungsregeln auf dem Server unter dem von Ihnen angegebenen Pfad bereitgestellt werden.

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

Methodenbasierte Regel

Verwenden Sie Add, um Ihre eigene Regellogik in einer Methode zu implementieren. Add macht RewriteContext verfügbar, wodurch die Verwendung von HttpContext in Ihrer Methode ermöglicht wird. RewriteContext.Result bestimmt, wie die zusätzliche Pipelineverarbeitung erfolgt. Legen Sie den Wert auf eines der RuleResult-Felder fest, die in der folgenden Tabelle beschrieben sind:

Umschreiben von Kontext – Ergebnisse Aktion
RuleResult.ContinueRules (Standardwert) Regeln weiter anwenden.
RuleResult.EndResponse Regeln nicht mehr anwenden und Antwort senden.
RuleResult.SkipRemainingRules Regeln nicht mehr anwenden, und den Kontext an die nächste Middleware senden.
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}"));
}

In der Beispiel-App wird eine Methode dargestellt, die Anforderungen für Pfade weiterleitet, die auf .xml enden. Wenn eine Anforderung für /file.xml erfolgt, wird sie zu /xmlfiles/file.xml umgeleitet. Der Statuscode wird auf 301 - Moved Permanently festgelegt. Wenn vom Browser eine neue Anforderung für /xmlfiles/file.xml gesendet wird, wird dem Client die Datei von Middleware für statische Dateien aus dem Ordner wwwroot/xmlfiles bereitgestellt. Legen Sie für eine Umleitung den Statuscode der Antwort explizit fest. Andernfalls wird ein Statuscode 200 – OK zurückgegeben, und die Umleitung findet nicht auf dem Client statt.

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

Bei diesem Ansatz können auch Anforderungen erneut generiert werden. In der Beispiel-App wird demonstriert, wie der Pfad für eine beliebige Textdateianforderung umgeschrieben wird, um die Textdatei file.txt aus dem Ordner wwwroot bereitzustellen. Middleware für statische Dateien stellt die Datei bereit, die auf dem aktualisierten Anforderungspfad basiert:

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

IRule-basierte Regel

Um Regellogik in einer Klasse zu nutzen, die die IRule-Schnittstelle implementiert, verwenden Sie Add. Wenn Sie IRule verwenden, können Sie flexibler entscheiden, ob Sie eine methodenbasierte Regel verwenden möchten. Ihre Implementierungsklasse kann einen Konstruktor enthalten, wodurch Sie Parameter für die ApplyRule-Methode übergeben können.

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

Die Werte für die Parameter in der Beispiel-App für extension und newPath werden auf verschiedene Bedingungen geprüft. extension muss einen Wert enthalten, der .png, .jpg oder .gif entspricht. Wenn newPath nicht gültig ist, wird ArgumentException nicht ausgelöst. Wenn eine Anforderung für image.png erfolgt, wird sie zu /png-images/image.png umgeleitet. Wenn eine Anforderung für image.jpg erfolgt, wird sie zu /jpg-images/image.jpg umgeleitet. Der Statuscode wird auf 301 - Moved Permanently festgelegt, und context.Result erhält die Anweisung, Verarbeitungsregeln zu beenden und die Antwort zu senden.

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

Ursprüngliche Anforderung: /image.png

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

Ursprüngliche Anforderung: /image.jpg

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

RegEx-Beispiele

Ziel RegEx-Zeichenfolge &
übereinstimmendes Beispiel
Ersetzungszeichenfolge &
Ausgabebeispiel
Umschreiben des Pfads in die Abfragezeichenfolge ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Entfernen des nachgestellten Schrägstrichs (.*)/$
/path/
$1
/path
Erzwingen des nachgestellten Schrägstrichs (.*[^/])$
/path
$1/
/path/
Vermeiden des Umschreibens von bestimmten Anforderungen ^(.*)(?<!\.axd)$ oder ^(?!.*\.axd$)(.*)$
Ja: /resource.htm
Nein: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Ändern der Anordnung von URL-Segmenten path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Ersetzen von URL-Segmenten ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

In diesem Artikel wird das Umschreiben von URLs beschrieben. Außerdem erhalten Sie Anweisungen zur Verwendung der URL-umschreibenden Middleware in ASP.NET Core-Apps.

Bei der URL-Umschreibung werden die Anforderungs-URLs verändert, die auf mindesten einer vordefinierten Regel basieren. Es wird eine Abstraktion zwischen den Speicherorten und Adressen von Ressourcen erstellt, sodass diese nicht eng miteinander verknüpft sind. Die URL-Neuschreibung ist hilfreich in verschiedenen Szenarios wie:

  • Kurzzeitiges oder permanentes Verschieben oder Ersetzen von Serverressourcen, sowie Erhalten von stabilen Locators für diese Ressourcen.
  • Verteilen der Verarbeitung von Anforderungen auf verschiedene Apps oder Bereiche einer App.
  • Entfernen, Hinzufügen oder Umorganisieren von URL-Segmenten bei eingehenden Anforderungen.
  • Optimieren von öffentlichen URLs für die Suchmaschinenoptimierung (Search Engine Optimization, SEO).
  • Gestatten der Verwendung von angezeigten öffentlichen URLs, um Besuchern zu helfen, den Inhalt vorherzusagen, der durch die Anforderung einer Ressource zurückgegeben wird.
  • Umleiten von unsicheren Anforderungen auf sichere Endpunkte.
  • Verhindern von Hotlinks zu externen Websites, die eine gehostete statische Ressource auf einer anderen Website verwenden, bei der die Ressource zu ihrem eigenen Inhalt verlinkt wird.

Hinweis

Wenn Sie URLs umschreiben, kann das negative Auswirkungen auf die Leistung einer App haben. Wenn möglich, sollten Sie so wenig Regeln wie möglich erstellen und darauf achten, dass diese nicht zu kompliziert sind.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Umleiten und Umschreiben von URLs

Der Unterschied zwischen dem Umleiten und Neu schreiben von URLs ist zwar gering, allerdings haben die beiden Verfahren sehr unterschiedliche Auswirkungen auf die Bereitstellung von Ressourcen für Clients. Die URL-umschreibenden Middleware von ASP.NET Core kann für beide Vorgänge verwendet werden.

Bei der Umleitung von URLs findet ein clientseitiger Vorgang statt, bei dem der Client angewiesen wird, auf eine Ressource unter einer anderen Adresse zuzugreifen, als die, die der Client ursprünglich angefordert hat. Dafür ist ein Roundtrip zum Server erforderlich. Die Umleitungs-URL, die an den Client zurückgegeben wird, wird in der Adressleiste des Browsers angezeigt, wenn der Client eine neue Anforderung an die Ressource sendet.

Wenn /resource auf /different-resourceumgeleitet wird, sendet der Server die Antwort, dass der Client die Ressource unter /different-resource abrufen soll. In der Antwort ist außerdem ein Statuscode enthalten, aus dem entnommen werden kann, ob die Umleitung temporär oder permanent ist.

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.

Wenn Anforderungen auf eine andere URL umgeleitet werden, muss angegeben werden, ob die Umleitung temporär oder permanent sein soll. Geben Sie hierzu den Statuscode mit der Antwort an:

  • Der Statuscode 301 - Moved Permanently wird verwendet, wenn der Ressource eine neue permanente URL zugewiesen wurde, und Sie dem Client die Anweisung geben möchten, dass alle zukünftigen Anforderungen an die Ressource die neue URL verwenden sollen. Der Client kann die Antwort zwischenspeichern und wiederverwenden, wenn der Statuscode 301 empfangen wird.

  • Der Statuscode 302 – Gefunden wird verwendet, wenn die Umleitung temporär ist oder sowieso Änderungen vorbehalten sind. Der Statuscode 302 teilt dem Client mit, dass die URL nicht gespeichert und nicht wiederverwendet werden soll.

Weitere Informationen zu Statuscodes finden Sie unter RFC 2616: Status Code Definitions.

Bei der Neuschreibung einer URL handelt es sich um einen serverseitigen Vorgang, bei dem eine Ressource von einer anderen Ressourcenadresse, als der vom Client angeforderten, bereitgestellt wird. Wenn eine URL neu geschrieben wird, ist kein Roundtrip zum Server erforderlich. Die neu geschriebene URL wird nicht an den Server zurückgegeben und nicht in der Adressleiste des Browsers angezeigt.

Wenn /resource in /different-resourceumgeschrieben wird, ruft der Server die Ressource intern ab und gibt sie zurück an /different-resource.

Auch wenn der Client die Ressource unter der neu geschriebene URL abrufen kann, erhält er nicht die Information, dass die Ressource unter der umgeschriebenen URL gespeichert ist, wenn er die Anforderung sendet und eine Antwort erhält.

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.

URL-umschreibende Beispiel-App

Mit der Beispiel-App können Sie die Features der Middleware zur URL-Neuschreibung testen. Die App wendet Umleitungs- und Neuschreibungsregeln an und zeigt die umgeleitete oder neu geschriebene URL für verschiedene Szenarios an.

Empfohlene Verwendung der URL-umschreibenden Middleware

Sie können Middleware zur URL-Neuschreibung verwenden, wenn die folgenden Ansätze nicht möglich sind:

Sie können die Middleware auch verwenden, wenn die App auf dem HTTP.sys-Server (früher als WebListener bezeichnet) gehostet wird.

Die Hauptgründe für die Verwendung der serverbasierten Technologien zur URL-Neuschreibung in IIS, Apache und Nginx sind:

  • Die Middleware unterstützt nicht alle Features dieser Module.

    Einige Features der Servermodule funktionieren nicht mit ASP.NET Core-Projekten – z.B. die Einschränkungen IsFile und IsDirectory des IIS-Neuschreibungsmoduls. Verwenden Sie in diesem Szenario stattdessen die Middleware.

  • Die Leistung der Middleware stimmt wahrscheinlich nicht mit der Leistung der Module überein.

    Benchmarking ist der einzige Weg, um sicher festzustellen, welcher Ansatz die Leistung am meisten beeinträchtigt oder ob die nachlassende Leistung nur geringfügig ist.

Package

Um die Middleware in Ihr Projekt einzuschließen, fügen Sie einen Paketverweis zum Microsoft.AspNetCore.App-Metapaket in der Projektdatei ein, die das Microsoft.AspNetCore.Rewrite-Paket enthält.

Wenn Sie das Microsoft.AspNetCore.AppMetapaket nicht verwenden, fügen Sie dem Paket einen Projekthinweis hinzuMicrosoft.AspNetCore.Rewrite.

Erweiterung und Optionen

Legen Sie URL-Neuschreibungs- und -Umleitungsregeln fest, indem Sie eine Instanz der RewriteOptions-Klasse erstellen und Erweiterungsmethoden für jede Neuschreibungsregel hinzufügen. Verketten Sie mehrere Regeln in der Reihenfolge miteinander, in der sie verarbeitet werden sollen. Die RewriteOptions werden an die Middleware zur URL-Neuschreibung übergeben, wenn diese mit UseRewriter zu der Anforderungspipeline hinzugefügt wird:

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

Umleitung einer Nicht-WWW-Anforderung an eine WWW-Anforderung

Drei Optionen ermöglichen der App, Nicht-www-Anforderungen an www umzuleiten:

  • AddRedirectToWwwPermanent: Die Anforderung wird dauerhaft an die Unterdomäne www umgeleitet, sofern die Anforderung nicht www ist. Wird mit dem Statuscode Status308PermanentRedirect umgeleitet.

  • AddRedirectToWww: Die Anforderung wird an die Unterdomäne www umgeleitet, sofern die eingehende Anforderung nicht www ist. Wird mit dem Statuscode Status307TemporaryRedirect umgeleitet. Eine Überladung ermöglicht es Ihnen, den Statuscode für die Antwort zu senden. Verwenden Sie ein Feld der StatusCodes-Klasse, um einen Statuscode zuzuweisen.

Umleitungs-URL

Verwenden Sie AddRedirect, um Anforderungen umzuleiten. Der erste Parameter enthält Ihren RegEx, damit dieser dem Pfad der eingehenden URL zugeordnet werden kann. Beim zweiten Parameter handelt es sich um eine Ersatzzeichenfolge. Der dritte Parameter gibt, falls vorhanden, den Statuscode an. Wenn Sie den Statuscode nicht angeben, wird standardmäßig 302 – Gefunden zurückgegeben, was bedeutet, dass die Ressource kurzzeitig verschoben oder ersetzt wurde.

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

Aktivieren Sie in Ihrem Browser die Entwicklertools, und senden Sie eine Anforderung an die Beispiel-App mit dem Pfad /redirect-rule/1234/5678. Der RegEx stimmt mit dem Anforderungspfad unter redirect-rule/(.*) überein, und der Pfad wird durch /redirected/1234/5678 ersetzt. Die Umleitungs-URL wird mit dem Statuscode 302 – Gefunden an den Client zurückgesendet. Unter der Umleitungs-URL sendet der Browser eine neue Anforderung, die in dessen Adressleiste angezeigt wird. Da keine Regel in der Beispiel-App mit der Umleitungs-URL übereinstimmt:

  • Die zweite Anforderung erhält die Antwort 200 – OK von der App.
  • Der Antworttext zeigt die Umleitungs-URL an.

Wenn eine URL weitergeleitet wird, wird ein Roundtrip zum Server ausgelöst.

Warnung

Seien Sie vorsichtig, wenn Sie Umleitungsregeln einrichten. Bei jeder Anforderung an die App werden Umleitungsregeln überprüft – auch nach einer Umleitung. Dabei kann schnell aus Versehen eine Dauerschleife von Umleitungen entstehen.

Ursprüngliche Anforderung: /redirect-rule/1234/5678

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

Der Teil des Ausdruck in Klammern wird als Erfassungsgruppe bezeichnet. Der Punkt (.) im Ausdruck steht für Übereinstimmung mit beliebigem Zeichen. Das Sternchen (*) steht für Übereinstimmung mit dem vorausgehenden Zeichen (keinmal oder mindestens einmal) . Daher werden die letzten beiden Pfadsegmente der URL (1234/5678) von der Erfassungsgruppe erfasst (.*). Alle Werte, die Sie in der Anforderungs-URL nach redirect-rule/ angeben, werden von dieser Erfassungsgruppe erfasst.

Erfassungsgruppen werden in der Ersetzungszeichenfolge mit dem Dollarzeichen ($) in die Zeichenfolge eingefügt. Danach folgt die Sequenznummer der Erfassung. Der erste Wert der Erfassungsgruppe wird mit $1 abgerufen, der zweite mit $2. Dies wird in Sequenzen für die Erfassungsgruppen Ihres RegEx weitergeführt. Nur eine Erfassungsgruppe ist in der Beispiel-App im RegEx der Umleitungsregel enthalten. Das bedeutet, dass es in die Ersetzungszeichenfolge nur eine Gruppe eingefügt wird, nämlich $1. Wenn die Regel angewendet wird, ändert sich die URL in /redirected/1234/5678.

URL-Umleitung an einen sicheren Endpunkt

Verwenden Sie AddRedirectToHttps, um HTTP-Anforderungen auf denselben Host und Pfad mithilfe des HTTPS-Protokolls umzuleiten. Wenn kein Statuscode angegeben wird, wird für die Middleware standardmäßig 302 – Gefunden zurückgegeben. Wenn kein Port angegeben ist:

  • Für die Middleware wird standardmäßig null zurückgegeben.
  • Das Schema ändert sich in https (HTTPS-Protokoll), und der Client hat über Port 443 Zugriff auf die Ressource.

Im folgenden Beispiel wird dargestellt, wie Sie den Statuscode 301 - Moved Permanently festlegen und den Port in 5001 ändern.

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

    app.UseRewriter(options);
}

Verwenden Sie AddRedirectToHttpsPermanent, um unsichere Anforderungen auf denselben Host und Pfad mit einem sicheren HTTPS-Protokoll auf Port 443 umzuleiten. Die Middleware legt den Statuscode auf 301 - Moved Permanently fest.

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

    app.UseRewriter(options);
}

Hinweis

Wenn Sie eine Umleitung an einen sicheren Endpunkt ohne weitere erforderliche Umleitungsregeln durchführen, wird empfohlen, Middleware für HTTPS-Umleitung zu verwenden. Weitere Informationen finden Sie im Artikel zum Erzwingen von HTTPS.

Anhand der Beispiel-App wird veranschaulicht, wie AddRedirectToHttps oder AddRedirectToHttpsPermanent verwendet werden sollen. Fügen Sie die Erweiterungsmethode zu den RewriteOptions hinzu. Senden Sie eine unsichere Anforderung an die App unter einer beliebigen URL. Schließen Sie die Sicherheitswarnung des Browsers, in der Sie darüber informiert werden, dass das selbstsignierte Zertifikat nicht vertrauenswürdig ist, oder erstellen sie eine Ausnahme, um dem Zertifikat zu vertrauen.

Ursprüngliche Anforderung über AddRedirectToHttps(301, 5001): http://localhost:5000/secure

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

Ursprüngliche Anforderung über AddRedirectToHttpsPermanent: http://localhost:5000/secure

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

Umschreiben einer URL

Erstellen Sie mithilfe von AddRewrite eine Regel zum Umschreiben von URLs. Der erste Parameter enthält den RegEx, damit dieser der eingehenden URL zugeordnet werden kann. Beim zweiten Parameter handelt es sich um eine Ersatzzeichenfolge. Der dritte Parameter (skipRemainingRules: {true|false}) teilt der Middleware mit, ob sie zusätzliche Umschreibungsregeln überspringen soll, wenn die aktuelle Regel angewendet wird.

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

Ursprüngliche Anforderung: /rewrite-rule/1234/5678

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

Das Zirkumflexzeichen (^) am Anfang des Ausdrucks bedeutet, dass die Übereinstimmung schon am Anfang des URL-Pfads beginnt.

In dem vorherigen Beispiel zu den Umleitungsregeln, redirect-rule/(.*), beginnt der RegEx nicht mit einem Zirkumflexzeichen (^). So kann für eine Übereinstimmung ein beliebiges Zeichen im Pfad vor redirect-rule/ stehen.

Pfad Match
/redirect-rule/1234/5678 Ja
/my-cool-redirect-rule/1234/5678 Ja
/anotherredirect-rule/1234/5678 Ja

Die Umschreibungsregel (^rewrite-rule/(\d+)/(\d+)) stimmt nur mit Pfaden überein, wenn sie mit rewrite-rule/ beginnen. Beachten Sie die unterschiedliche Übereinstimmung in der folgenden Tabelle:

Pfad Match
/rewrite-rule/1234/5678 Ja
/my-cool-rewrite-rule/1234/5678 Nein
/anotherrewrite-rule/1234/5678 Nein

Auf den ^rewrite-rule/-Teil des Ausdruck folgen zwei Erfassungsgruppen: (\d+)/(\d+). \d steht für Übereinstimmung mit einer Ziffer (Zahl) . Das Pluszeichen (+) steht für match one or more of the preceding character (Übereinstimmung mit mindestens einem vorausgehenden Zeichen). Aus diesem Grund muss die URL eine Zahl enthalten, auf die ein Schrägstrich und eine weitere Zahl folgt. Die Erfassungsgruppen werden in die umgeschriebene URL als $1 und $2 eingefügt. Über die Ersetzungszeichenfolge der Neuschreibungsregel werden die Erfassungsgruppen in die Abfragezeichenfolge eingefügt. Der angeforderte /rewrite-rule/1234/5678-Pfad wird umgeschrieben, um eine Ressource unter /rewritten?var1=1234&var2=5678 abzurufen. Wenn es in der ursprünglichen Anforderung eine Abfragezeichenfolge gibt, bleibt diese erhalten, wenn die URL umgeschrieben wird.

Es gibt keinen Roundtrip zum Server, um die Ressource abzurufen. Wenn es die Ressource gibt, wird sie abgerufen und dem Client mit dem Statuscode 200 – OK zurückgegeben. Da der Client nicht umgeleitet wird, ändert sich die URL in der Adressleiste des Browsers nicht. Clients können nicht erkennen, dass ein Vorgang zum erneuten Schreiben einer URL auf dem Server stattgefunden hat.

Hinweis

Verwenden Sie skipRemainingRules: true, wo immer das möglich ist, da das Abgleichen von Regeln rechnerisch sehr aufwendig ist und die Antwortzeit der App erhöht. Führen Sie folgende Schritte aus, um die schnellsten App-Antwortzeiten zu erreichen:

  • Sortieren Sie Neuschreibungsregeln von der am häufigsten abgeglichenen Regel zu der am seltensten abgeglichenen Regel.
  • Überspringen Sie die Verarbeitung der übrigen Regeln, wenn es zu einer Übereinstimmung kommt und keine zusätzlichen Regelverarbeitungen erforderlich sind.

Apache: „mod_rewrite“

Wenden Sie die Apache-Regeln „mod_rewrite“ mit AddApacheModRewrite an. Vergewissern Sie sich, dass die Regeldatei mit der App bereitgestellt wird. Weitere Informationen zu diesen Regeln finden Sie unter Apache: „mod_rewrite“.

Zum Lesen der Regeldatei ApacheModRewrite.txt wird StreamReader verwendet:

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

Die Beispiel-App leitet Anforderungen von /apache-mod-rules-redirect/(.\*) auf /redirected?id=$1 um. Der Antwortstatuscode lautet 302 – Gefunden.

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

Ursprüngliche Anforderung: /apache-mod-rules-redirect/1234

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

Die Middleware unterstützt die folgenden Servervariablen für die Apache „mod_rewrite“:

  • 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
  • TIME
  • TIME_DAY
  • TIME_HOUR
  • TIME_MIN
  • TIME_MON
  • TIME_SEC
  • TIME_WDAY
  • TIME_YEAR

Regeln zum IIS-Umschreibungsmodul

Um denselben Regelsatz zu verwenden, der für das IIS-Moduls für URL-Neuschreibung gilt, verwenden Sie AddIISUrlRewrite. Vergewissern Sie sich, dass die Regeldatei mit der App bereitgestellt wird. Geben Sie der Middleware nicht die Anweisung, die web.config-Datei der App zu verwenden, wenn sie auf der Windows Server-IIS ausgeführt wird. Bei IIS sollten diese Regeln außerhalb der web.config-Datei der App gespeichert werden, um Konflikte mit dem IIS-Neuschreibungsmodul zu vermeiden. Weitere Informationen und Beispiele zu den Regeln zum IIS-Umschreibungsmodul finden Sie unter Using Url Rewrite Module 2.0 (Verwenden des URL-Umschreibungsmoduls 2.0) und URL Rewrite Module Configuration Reference (Konfigurationsreferenz des URL-Umschreibungsmoduls).

Zum Lesen der Regeldatei IISUrlRewrite.xml wird StreamReader verwendet:

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

Die Beispiel-App schreibt Anforderungen von /iis-rules-rewrite/(.*) in /rewritten?id=$1 um. Die Antwort wird an den Client mit dem Statuscode 200 – OK gesendet.

<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>

Ursprüngliche Anforderung: /iis-rules-rewrite/1234

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

Wenn Sie über ein aktives IIS-Umschreibungsmodul verfügen, für das die Regeln auf Serverebene konfiguriert sind, die negative Auswirkungen auf Ihre App hätten, können Sie das IIS-Umschreibungsmodul für die App deaktivieren. Weitere Informationen finden Sie unter Disabling IIS modules (Deaktivieren von IIS-Modulen).

Nicht unterstützte Features

Die im Lieferumfang von ASP.NET Core 2.x enthaltene Middleware unterstützt die folgenden Features des IIS-URL-Umschreibungsmoduls nicht:

  • Ausgehende Regeln
  • Benutzerdefinierte Servervariablen
  • Platzhalter
  • LogRewrittenUrl

Unterstützte Servervariablen

Die Middleware unterstützt die folgenden Servervariablen für das IIS-URL-Umschreibungsmodul:

  • 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

Hinweis

Sie können IFileProvider auch über PhysicalFileProvider abrufen. Über diesen Ansatz können Sie flexibler einen Speicherort für die Dateien der Umschreibungsregeln auswählen. Vergewissern Sie sich, dass die Dateien zu den Umschreibungsregeln auf dem Server unter dem von Ihnen angegebenen Pfad bereitgestellt werden.

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

Methodenbasierte Regel

Verwenden Sie Add, um Ihre eigene Regellogik in einer Methode zu implementieren. Add macht RewriteContext verfügbar, wodurch die Verwendung von HttpContext in Ihrer Methode ermöglicht wird. RewriteContext.Result bestimmt, wie die zusätzliche Pipelineverarbeitung erfolgt. Legen Sie den Wert auf eines der RuleResult-Felder fest, die in der folgenden Tabelle beschrieben sind:

Umschreiben von Kontext – Ergebnisse Aktion
RuleResult.ContinueRules (Standardwert) Regeln weiter anwenden.
RuleResult.EndResponse Regeln nicht mehr anwenden und Antwort senden.
RuleResult.SkipRemainingRules Regeln nicht mehr anwenden, und den Kontext an die nächste Middleware senden.
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}"));
}

In der Beispiel-App wird eine Methode dargestellt, die Anforderungen für Pfade weiterleitet, die auf .xml enden. Wenn eine Anforderung für /file.xml erfolgt, wird sie zu /xmlfiles/file.xml umgeleitet. Der Statuscode wird auf 301 - Moved Permanently festgelegt. Wenn vom Browser eine neue Anforderung für /xmlfiles/file.xml gesendet wird, wird dem Client die Datei von Middleware für statische Dateien aus dem Ordner wwwroot/xmlfiles bereitgestellt. Legen Sie für eine Umleitung den Statuscode der Antwort explizit fest. Andernfalls wird ein Statuscode 200 – OK zurückgegeben, und die Umleitung findet nicht auf dem Client statt.

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

Bei diesem Ansatz können auch Anforderungen erneut generiert werden. In der Beispiel-App wird demonstriert, wie der Pfad für eine beliebige Textdateianforderung umgeschrieben wird, um die Textdatei file.txt aus dem Ordner wwwroot bereitzustellen. Middleware für statische Dateien stellt die Datei bereit, die auf dem aktualisierten Anforderungspfad basiert:

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

IRule-basierte Regel

Um Regellogik in einer Klasse zu nutzen, die die IRule-Schnittstelle implementiert, verwenden Sie Add. Wenn Sie IRule verwenden, können Sie flexibler entscheiden, ob Sie eine methodenbasierte Regel verwenden möchten. Ihre Implementierungsklasse kann einen Konstruktor enthalten, wodurch Sie Parameter für die ApplyRule-Methode übergeben können.

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

Die Werte für die Parameter in der Beispiel-App für extension und newPath werden auf verschiedene Bedingungen geprüft. extension muss einen Wert enthalten, der .png, .jpg oder .gif entspricht. Wenn newPath nicht gültig ist, wird ArgumentException nicht ausgelöst. Wenn eine Anforderung für image.png erfolgt, wird sie zu /png-images/image.png umgeleitet. Wenn eine Anforderung für image.jpg erfolgt, wird sie zu /jpg-images/image.jpg umgeleitet. Der Statuscode wird auf 301 - Moved Permanently festgelegt, und context.Result erhält die Anweisung, Verarbeitungsregeln zu beenden und die Antwort zu senden.

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

Ursprüngliche Anforderung: /image.png

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

Ursprüngliche Anforderung: /image.jpg

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

RegEx-Beispiele

Ziel RegEx-Zeichenfolge &
übereinstimmendes Beispiel
Ersetzungszeichenfolge &
Ausgabebeispiel
Umschreiben des Pfads in die Abfragezeichenfolge ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Entfernen des nachgestellten Schrägstrichs (.*)/$
/path/
$1
/path
Erzwingen des nachgestellten Schrägstrichs (.*[^/])$
/path
$1/
/path/
Vermeiden des Umschreibens von bestimmten Anforderungen ^(.*)(?<!\.axd)$ oder ^(?!.*\.axd$)(.*)$
Ja: /resource.htm
Nein: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Ändern der Anordnung von URL-Segmenten path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Ersetzen von URL-Segmenten ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

Zusätzliche Ressourcen