Ponowne zapisywanie oprogramowania pośredniczącego w adresie URL w programie ASP.NET Core

Autor: Kirk Larkin i Rick Anderson

W tym artykule przedstawiono ponowne zapisywanie adresów URL z instrukcjami dotyczącymi używania oprogramowania pośredniczącego ponownego zapisywania adresów URL w aplikacjach ASP.NET Core.

Ponowne zapisywanie adresów URL to czynność modyfikowania adresów URL żądań na podstawie co najmniej jednej wstępnie zdefiniowanej reguły. Ponowne zapisywanie adresów URL powoduje utworzenie abstrakcji między lokalizacjami zasobów a ich adresami, dzięki czemu lokalizacje i adresy nie są ściśle połączone. Ponowne zapisywanie adresów URL jest przydatne w kilku scenariuszach:

  • Tymczasowe lub trwałe przenoszenie lub zastępowanie zasobów serwera i utrzymywanie stabilnych lokalizatorów dla tych zasobów.
  • Podziel przetwarzanie żądań między różne aplikacje lub obszary jednej aplikacji.
  • Usuwanie, dodawanie lub reorganizacja segmentów adresów URL dla żądań przychodzących.
  • Optymalizowanie publicznych adresów URL na potrzeby optymalizacji aparatu wyszukiwania (SEO).
  • Zezwól na używanie przyjaznych publicznych adresów URL, aby ułatwić odwiedzającym przewidywanie zawartości zwracanej przez żądanie zasobu.
  • Przekieruj niezabezpieczone żądania do bezpiecznych punktów końcowych.
  • Zapobiegaj łączeniu gorąca, w którym witryna zewnętrzna używa hostowanego zasobu statycznego w innej witrynie, łącząc zasób z własną zawartością.

Ponowne zapisywanie adresów URL może zmniejszyć wydajność aplikacji. Ogranicz liczbę i złożoność reguł.

Przekierowanie adresu URL i ponowne zapisywanie adresów URL

Różnica w sformułowaniu między przekierowywaniem adresów URL a ponownym zapisywaniem adresów URL jest subtelna, ale ma ważne konsekwencje dla udostępniania zasobów klientom. ASP.NET Core adres URL ponownego zapisywania oprogramowania pośredniczącego jest w stanie sprostać potrzebom obu tych programów.

Przekierowanie adresu URL obejmuje operację po stronie klienta, gdzie klient jest poinstruowany, aby uzyskać dostęp do zasobu pod innym adresem niż klient pierwotnie zażądał. Wymaga to rundy na serwerze. Adres URL przekierowania zwrócony do klienta jest wyświetlany na pasku adresu przeglądarki, gdy klient wysyła nowe żądanie dla zasobu.

Jeśli /resource nastąpi przekierowanie do /different-resourceusługi , serwer odpowiada, że klient powinien uzyskać zasób /different-resource z kodem stanu wskazującym, że przekierowanie jest tymczasowe lub trwałe.

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.

Podczas przekierowywania żądań do innego adresu URL wskaż, czy przekierowanie jest trwałe, czy tymczasowe, określając kod stanu z odpowiedzią:

  • Kod 301 - Moved Permanently stanu jest używany, gdy zasób ma nowy, trwały adres URL i że wszystkie przyszłe żądania zasobu powinny używać nowego adresu URL. Klient może buforowania i ponownego użycia odpowiedzi po odebraniu kodu stanu 301.

  • Kod 302 - Found stanu jest używany, gdy przekierowanie jest tymczasowe lub zwykle może ulec zmianie. Kod stanu 302 wskazuje klientowi, aby nie przechowywał adresu URL i używał go w przyszłości.

Aby uzyskać więcej informacji na temat kodów stanu, zobacz RFC 9110: Definicje kodu stanu.

Ponowne zapisywanie adresu URL to operacja po stronie serwera, która udostępnia zasób z innego adresu zasobu niż żądany przez klienta. Ponowne zapisywanie adresu URL nie wymaga rundy na serwerze. Przepisany adres URL nie jest zwracany do klienta i nie jest wyświetlany na pasku adresu przeglądarki.

Jeśli /resource element zostanie przepisany do /different-resourceelementu , serwer wewnętrznie pobiera i zwraca zasób pod adresem /different-resource.

Mimo że klient może być w stanie pobrać zasób pod adresem URL przepisanego, klient nie jest informowany, że zasób istnieje pod adresem URL przepisanym, gdy wysyła żądanie i odbiera odpowiedź.

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.

Ponowne zapisywanie adresów URL przykładowej aplikacji

Zapoznaj się z funkcjami adresu URL Ponowne zapisywanie oprogramowania pośredniczącego za pomocą przykładowej aplikacji. Aplikacja stosuje reguły przekierowania i ponownego zapisywania oraz wyświetla przekierowany lub przepisany adres URL w kilku scenariuszach.

Kiedy należy używać oprogramowania pośredniczącego ponownego zapisywania adresów URL

Użyj oprogramowania pośredniczącego ponownego zapisywania adresów URL, jeśli następujące podejścia nie są zadowalające:

Użyj adresu URL ponownego zapisywania oprogramowania pośredniczącego, gdy aplikacja jest hostowana na serwerze HTTP.sys.

Główne przyczyny używania technologii ponownego zapisywania adresów URL opartych na serwerze w usługach IIS, Apache i Nginx są następujące:

  • Oprogramowanie pośredniczące nie obsługuje pełnych funkcji tych modułów.

    Niektóre funkcje modułów serwera nie działają z projektami ASP.NET Core, takimi jak IsFile i IsDirectory ograniczenia modułu ponownego zapisywania usług IIS. W tych scenariuszach należy zamiast tego użyć oprogramowania pośredniczącego.

  • Wydajność oprogramowania pośredniczącego prawdopodobnie nie jest zgodna z wydajnością modułów.

    Benchmarking jest jedynym sposobem, aby wiedzieć z pewnością, który podejście obniża wydajność najbardziej lub jeśli obniżona wydajność jest nieznaczna.

Rozszerzenia i opcje

Ustanów reguły ponownego zapisywania adresów URL i przekierowywania, tworząc wystąpienie klasy RewriteOptions przy użyciu metod rozszerzeń dla każdej reguły ponownego zapisywania. Łączenie wielu reguł w kolejności ich przetwarzania. Element RewriteOptions jest przekazywany do adresu URL Ponowne zapisywanie oprogramowania pośredniczącego, ponieważ jest on dodawany do potoku żądania za pomocą polecenia UseRewriter:

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

W poprzednim kodzie MethodRules jest klasą zdefiniowaną przez użytkownika. Więcej informacji można znaleźć RewriteRules.cs w tym artykule.

Przekieruj nie-www na www

Trzy opcje umożliwiają aplikacji przekierowywanie żądań niezwiązanychwww z żądaniami do www:

Przekierowywanie adresów URL

Służy AddRedirect do przekierowywania żądań. Pierwszy parametr zawiera wyrażenie regularne platformy .NET (Regex) do dopasowywania w ścieżce przychodzącego adresu URL. Drugi parametr to ciąg zastępczy. Trzeci parametr, jeśli jest obecny, określa kod stanu. Jeśli kod stanu nie jest określony, kod stanu jest domyślnie ustawiony na 302 — Znaleziono, co oznacza, że zasób jest tymczasowo przenoszony lub zastępowany.

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

W przeglądarce z włączonymi narzędziami deweloperskich prześlij żądanie do przykładowej aplikacji ze ścieżką /redirect-rule/1234/5678. Wyrażenie regularne pasuje do ścieżki żądania w pliku redirect-rule/(.*), a ścieżka jest zastępowana ciągiem /redirected/1234/5678. Adres URL przekierowania jest wysyłany z powrotem do klienta z kodem stanu 302 — Znaleziono . Przeglądarka wysyła nowe żądanie pod adresem URL przekierowania, które jest wyświetlane na pasku adresu przeglądarki. Ponieważ w adresie URL przekierowania nie są zgodne żadne reguły w przykładowej aplikacji:

  • Drugie żądanie odbiera odpowiedź 200 — OK z aplikacji.
  • Treść odpowiedzi zawiera adres URL przekierowania.

Podczas przekierowywania adresu URL następuje zaokrąglenie do serwera.

Ostrzeżenie

Podczas ustanawiania reguł przekierowania należy zachować ostrożność. Reguły przekierowania są oceniane dla każdego żądania do aplikacji, w tym po przekierowaniu. Łatwo jest przypadkowo utworzyć pętlę nieskończonych przekierowań.

Część wyrażenia zawartego w nawiasach jest nazywana grupą przechwytywania. Kropka (.) wyrażenia oznacza dopasowanie dowolnego znaku. Gwiazdka (*) wskazuje dopasowanie poprzedniego znaku zero lub więcej razy. W związku z tym ostatnie dwa segmenty ścieżki adresu URL są 1234/5678przechwytywane przez grupę (.*)przechwytywania . Dowolna wartość podana w adresie URL żądania po redirect-rule/ przechwyceniu przez tę pojedynczą grupę przechwytywania.

W ciągu zastępczym przechwycone grupy są wstrzykiwane do ciągu znakiem dolara ($), a następnie numerem sekwencji przechwytywania. Pierwsza wartość grupy przechwytywania jest uzyskiwana za pomocą $1elementu , drugiego z elementami $2i są one kontynuowane w sekwencji dla grup przechwytywania w wyrażeniu regularnym. W wyrażeniu redirect-rule/(.*)regularnym reguły przekierowania istnieje tylko jedna przechwycona grupa, więc w ciągu zastępczym znajduje się tylko jedna grupa, czyli $1. Po zastosowaniu reguły adres URL zmieni się na /redirected/1234/5678.

Spróbuj użyć /redirect-rule/1234/5678 narzędzi przeglądarki na karcie sieci.

Przekierowanie adresu URL do bezpiecznego punktu końcowego

Użyj polecenia AddRedirectToHttps , aby przekierować żądania HTTP do tego samego hosta i ścieżki przy użyciu protokołu HTTPS. Jeśli kod stanu nie zostanie podany, oprogramowanie pośredniczące domyślnie ma wartość 302 — Znaleziono. Jeśli port nie jest podany:

  • Domyślnie oprogramowanie pośredniczące ma wartość null.
  • Schemat zmienia się na https (protokół HTTPS), a klient uzyskuje dostęp do zasobu na porcie 443.

W poniższym przykładzie pokazano, jak ustawić kod 301 - Moved Permanently stanu na i zmienić port na port HTTPS używany przez Kestrel hosta lokalnego. W środowisku produkcyjnym port HTTPS ma wartość null:

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

Służy AddRedirectToHttpsPermanent do przekierowywania niezabezpieczonych żądań do tego samego hosta i ścieżki przy użyciu bezpiecznego protokołu HTTPS na porcie 443. Oprogramowanie pośredniczące ustawia kod stanu na 301 - Moved Permanently.

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

Uwaga

Podczas przekierowywania do bezpiecznego punktu końcowego bez wymagania dodatkowych reguł przekierowania zalecamy użycie oprogramowania pośredniczącego przekierowania HTTPS. Aby uzyskać więcej informacji, zobacz Wymuszanie protokołu HTTPS.

Przykładowa aplikacja pokazuje, jak używać polecenia AddRedirectToHttps lub AddRedirectToHttpsPermanent. Utwórz niezabezpieczone żądanie HTTP do aplikacji pod adresem http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz. Podczas testowania przekierowania HTTP do HTTPS za pomocą hosta lokalnego:

  • Użyj adresu URL HTTP, który ma inny port niż adres URL HTTPS. Adres URL HTTP znajduje się w Properties/launchSettings.json pliku .
  • s Usunięcie elementu z https://localhost/{port} nie powiedzie się, ponieważ host lokalny nie odpowiada na porcie HTTP na port HTTPS.

Na poniższej ilustracji przedstawiono obraz narzędzi przeglądarki F12 żądania http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz użycia poprzedniego kodu:

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

Regenerowanie adresów URL

Użyj AddRewrite polecenia , aby utworzyć regułę na potrzeby ponownego zapisywania adresów URL. Pierwszy parametr zawiera wyrażenie regularne do dopasowywania w przychodzącej ścieżce adresu URL. Drugi parametr to ciąg zastępczy. Trzeci parametr , wskazuje oprogramowanie pośredniczące, skipRemainingRules: {true|false}czy pominąć dodatkowe reguły ponownego zapisywania, jeśli jest stosowana bieżąca reguła.

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

Spróbuj wysłać żądanie do https://redirect6.azurewebsites.net/rewrite-rule/1234/5678

Daszek (^) na początku wyrażenia oznacza, że dopasowanie rozpoczyna się na początku ścieżki adresu URL.

We wcześniejszym przykładzie z regułą redirect-rule/(.*)przekierowania nie ma karetki (^) na początku wyrażenia regularnego. W związku z tym wszelkie znaki mogą poprzedzać redirect-rule/ ścieżkę pomyślnego dopasowania.

Ścieżka Match
/redirect-rule/1234/5678 Tak
/my-cool-redirect-rule/1234/5678 Tak
/anotherredirect-rule/1234/5678 Tak

Reguła ponownego zapisywania, ^rewrite-rule/(\d+)/(\d+), pasuje tylko do ścieżek, jeśli zaczynają się od rewrite-rule/. W poniższej tabeli zwróć uwagę na różnicę w dopasowywaniu.

Ścieżka Match
/rewrite-rule/1234/5678 Tak
/my-cool-rewrite-rule/1234/5678 Nie.
/anotherrewrite-rule/1234/5678 Nie.

^rewrite-rule/ Po części wyrażenia istnieją dwie grupy przechwytywania: (\d+)/(\d+). Oznacza \d to dopasowanie cyfry (liczby). Znak plus (+) oznacza dopasowanie co najmniej jednego z powyższych znaków. W związku z tym adres URL musi zawierać liczbę, po której następuje ukośnik do przodu, po którym następuje kolejna liczba. Te grupy przechwytywania są wstrzykiwane do przepisanego adresu URL jako $1 i $2. Ciąg zastępczy reguły ponownej zapisywania umieszcza przechwycone grupy w ciągu zapytania. Żądana ścieżka /rewrite-rule/1234/5678 zostanie przepisana, aby zwrócić zasób pod adresem /rewritten?var1=1234&var2=5678. Jeśli ciąg zapytania jest obecny w oryginalnym żądaniu, zostanie on zachowany, gdy adres URL zostanie przepisany.

Nie ma rundy na serwerze, aby zwrócić zasób. Jeśli zasób istnieje, jest pobierany i zwracany do klienta z kodem stanu 200 — OK . Ponieważ klient nie jest przekierowywany, adres URL na pasku adresu przeglądarki nie zmienia się. Klienci nie mogą wykryć, że na serwerze wystąpiła operacja ponownego zapisywania adresu URL.

Porady dotyczące wydajności dotyczące ponownego zapisywania i przekierowywania adresów URL

Aby uzyskać najszybszą odpowiedź:

  • Kolejność ponownego zapisywania reguł z najczęściej dopasowywanej reguły do najmniej często dopasowywanej reguły.
  • Używaj skipRemainingRules: true zawsze, gdy jest to możliwe, ponieważ pasujące reguły są kosztowne w obliczeniach i zwiększają czas odpowiedzi aplikacji. Pomiń przetwarzanie pozostałych reguł, gdy wystąpi dopasowanie i nie jest wymagane żadne dodatkowe przetwarzanie reguł.

Ostrzeżenie

Złośliwy użytkownik może zapewnić kosztowne przetwarzanie danych wejściowych w celu spowodowania RegularExpressionsataku typu "odmowa usługi". ASP.NET podstawowe interfejsy API platformy, które używają RegularExpressions przekroczenia limitu czasu. Na przykład klasy RedirectRule i RewriteRule przechodzą w jeden drugi limit czasu.

Apache mod_rewrite

Zastosuj reguły usługi Apache mod_rewrite za pomocą polecenia AddApacheModRewrite. Upewnij się, że plik reguł został wdrożony z aplikacją. Aby uzyskać więcej informacji i przykłady reguł mod_rewrite, zobacz Apache mod_rewrite.

Element służy StreamReader do odczytywania reguł z pliku reguł ApacheModRewrite.txt :

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

Przykładowa aplikacja przekierowuje żądania z /apache-mod-rules-redirect/(.\*) do /redirected?id=$1. Kod stanu odpowiedzi to 302 — Znaleziono.

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

Spróbuj wysłać żądanie do https://redirect6.azurewebsites.net/apache-mod-rules-redirect/1234

Oprogramowanie pośredniczące Apache obsługuje następujące zmienne serwera Apache mod_rewrite:

  • CONN_REMOTE_ADDR
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_FORWARDED
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_USER_AGENT
  • HTTPS
  • Protokół 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

Reguły ponownego zapisywania modułów adresów URL usług IIS

Aby użyć tego samego zestawu reguł, który ma zastosowanie do modułu ponownego zapisywania adresów URL usług IIS, użyj polecenia AddIISUrlRewrite. Upewnij się, że plik reguł został wdrożony z aplikacją. Nie należy kierować oprogramowania pośredniczącego do używania pliku web.config aplikacji podczas uruchamiania w usługach IIS systemu Windows Server. W przypadku usług IIS te reguły powinny być przechowywane poza plikiem web.config aplikacji, aby uniknąć konfliktów z modułem Ponowne zapisywanie usług IIS. Aby uzyskać więcej informacji i przykłady reguł modułu ponownego zapisywania adresów URL usług IIS, zobacz Using Url Rewrite Module 2.0 and URL Rewrite Module Configuration Reference (Używanie modułu ponownego zapisywania adresów URL w wersji 2.0 ) i URL Rewrite Module Reference (Dokumentacja konfiguracji modułu ponownego zapisywania adresów URL).

Element A StreamReader służy do odczytywania reguł z IISUrlRewrite.xml pliku reguł:

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

Przykładowa aplikacja ponownie zapisuje żądania z /iis-rules-rewrite/(.*) do /rewritten?id=$1. Odpowiedź jest wysyłana do klienta z kodem stanu 200 — OK .

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

Spróbuj wysłać żądanie do https://redirect6.azurewebsites.net/iis-rules-rewrite/xyz

Aplikacje, które mają aktywny moduł ponownego zapisywania usług IIS z skonfigurowanymi regułami na poziomie serwera, które mają wpływ na aplikację w niepożądany sposób:

  • Rozważ wyłączenie modułu ponownego zapisywania usług IIS dla aplikacji.
  • Aby uzyskać więcej informacji, zobacz Wyłączanie modułów usług IIS.

Nieobsługiwane funkcje

Oprogramowanie pośredniczące nie obsługuje następujących funkcji modułu ponownego zapisywania adresów URL usług IIS:

  • Reguły ruchu wychodzącego
  • Niestandardowe zmienne serwera
  • Symbole wieloznaczne
  • LogRewrittenUrl

Obsługiwane zmienne serwera

Oprogramowanie pośredniczące obsługuje następujące zmienne serwera modułu ponownego zapisywania adresów URL usług IIS:

  • 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

IFileProvidermożna uzyskać za pośrednictwem .PhysicalFileProvider Takie podejście może zapewnić większą elastyczność lokalizacji plików reguł ponownego zapisywania. Upewnij się, że pliki reguł ponownego zapisywania są wdrażane na serwerze w podanej ścieżce.

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

Reguła oparta na metodzie

Służy Add do implementowania niestandardowej logiki reguł w metodzie. Add uwidacznia element RewriteContext, który udostępnia HttpContext element do użycia w metodach przekierowania. Właściwość RewriteContext.Result określa sposób obsługi dodatkowego przetwarzania potoku. Ustaw wartość na jedno z RuleResult pól opisanych w poniższej tabeli.

Wynik ponownego zapisywania kontekstu Akcja
RuleResult.ContinueRules (domyślne) Kontynuuj stosowanie reguł.
RuleResult.EndResponse Przestań stosować reguły i wysyłać odpowiedź.
RuleResult.SkipRemainingRules Przestań stosować reguły i wysyłać kontekst do następnego oprogramowania pośredniczącego.
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();

Przykładowa aplikacja demonstruje metodę, która przekierowuje żądania dla ścieżek zakończonych ciągiem .xml. Po wysłaniu żądania dla elementu /file.xml:

  • Żądanie jest przekierowywane do /xmlfiles/file.xml
  • Kod stanu jest ustawiony na 301 - Moved Permanentlywartość . Gdy przeglądarka wysyła nowe żądanie dla /xmlfiles/file.xmlprogramu , oprogramowanie pośredniczące plików statycznych udostępnia klientowi plik z folderu wwwroot/xmlfiles . W przypadku przekierowania jawnie ustaw kod stanu odpowiedzi. W przeciwnym razie zwracany jest kod stanu 200 — OK, a przekierowanie nie występuje na kliencie.

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

Takie podejście może również ponownie pisać żądania. Przykładowa aplikacja demonstruje ponowne zapisywanie ścieżki dla dowolnego żądania pliku tekstowego w celu obsłużenia pliku tekstowego file.txt z folderu wwwroot. Oprogramowanie pośredniczące plików statycznych obsługuje plik na podstawie zaktualizowanej ścieżki żądania:

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

Reguła oparta na protokole IRule

Służy Add do używania logiki reguł w klasie, która implementuje IRule interfejs. IRule zapewnia większą elastyczność przy użyciu podejścia opartego na metodzie. Klasa implementacji może zawierać konstruktor, który umożliwia przekazywanie parametrów dla ApplyRule metody.

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

Wartości parametrów w przykładowej aplikacji dla extension elementu i newPath są sprawdzane pod kątem spełnienia kilku warunków. Wartość extension musi zawierać wartość , a wartość musi mieć .pngwartość , .jpglub .gif. Jeśli element newPath jest nieprawidłowy, zostanie zgłoszony element ArgumentException . Jeśli żądanie zostanie wykonane dla image.pngelementu , żądanie zostanie przekierowane do /png-images/image.png. Jeśli żądanie zostanie wykonane dla image.jpgelementu , żądanie zostanie przekierowane do /jpg-images/image.jpg. Kod stanu jest ustawiony na 301 - Moved Permanentlywartość , a context.Result właściwość jest ustawiona na wartość , aby zatrzymać przetwarzanie reguł i wysłać odpowiedź.

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

Spróbuj:

  • Żądanie PNG: https://redirect6.azurewebsites.net/image.png
  • Żądanie JPG: https://redirect6.azurewebsites.net/image.jpg

Przykłady wyrażeń regularnych

Goal Ciąg wyrażeń regularnych i
Przykład dopasowania
Ciąg zastępczy i
Przykład danych wyjściowych
Ponowne zapisywanie ścieżki do elementu querystring ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Pasek końcowy ukośnik ^path2/(.*)/$
/path2/xyz/
$1
/path2/xyz
Wymuszanie ukośnika końcowego ^path3/(.*[^/])$
/path3/xyz
$1/
/path3/xyz/
Unikaj ponownego zapisywania określonych żądań ^(.*)(?<!\.axd)$ Lub
^(?!.*\.axd$)(.*)$
Tak: /path4/resource.htm
Nr: /path4/resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Ponowne rozmieszczanie segmentów adresów URL path5/(.*)/(.*)/(.*)
path5/1/2/3
path5/$3/$2/$1
path5/3/2/1
Zastępowanie segmentu adresu URL ^path6/(.*)/segment2/(.*)
^path6/segment1/segment2/segment3
path6/$1/replaced/$2
/path6/segment1/replaced/segment3

Linki w poprzedniej tabeli używają następującego kodu wdrożonego na platformie Azure:

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

W większości powyższych przykładów wyrażeń regularnych literał path jest używany do tworzenia unikatowych reguł ponownego zapisywania testowalnego dla wdrożonego przykładu. Zazwyczaj wyrażenie regularne nie zawiera pathwyrażenia regularnego. Zobacz na przykład tabelę przykładów wyrażeń regularnych .

W tym dokumencie przedstawiono ponowne zapisywanie adresów URL z instrukcjami dotyczącymi używania oprogramowania pośredniczącego ponownego zapisywania adresów URL w aplikacjach ASP.NET Core.

Ponowne zapisywanie adresów URL to czynność modyfikowania adresów URL żądań na podstawie co najmniej jednej wstępnie zdefiniowanej reguły. Ponowne zapisywanie adresów URL powoduje utworzenie abstrakcji między lokalizacjami zasobów a ich adresami, dzięki czemu lokalizacje i adresy nie są ściśle połączone. Ponowne zapisywanie adresów URL jest przydatne w kilku scenariuszach:

  • Tymczasowe lub trwałe przenoszenie lub zastępowanie zasobów serwera i utrzymywanie stabilnych lokalizatorów dla tych zasobów.
  • Podziel przetwarzanie żądań między różne aplikacje lub obszary jednej aplikacji.
  • Usuwanie, dodawanie lub reorganizacja segmentów adresów URL dla żądań przychodzących.
  • Optymalizowanie publicznych adresów URL na potrzeby optymalizacji aparatu wyszukiwania (SEO).
  • Zezwól na używanie przyjaznych publicznych adresów URL, aby ułatwić odwiedzającym przewidywanie zawartości zwracanej przez żądanie zasobu.
  • Przekieruj niezabezpieczone żądania do bezpiecznych punktów końcowych.
  • Zapobiegaj łączeniu gorąca, w którym witryna zewnętrzna używa hostowanego zasobu statycznego w innej witrynie, łącząc zasób z własną zawartością.

Uwaga

Ponowne zapisywanie adresów URL może zmniejszyć wydajność aplikacji. W miarę możliwości ogranicz liczbę i złożoność reguł.

Wyświetl lub pobierz przykładowy kod (jak pobrać)

Przekierowanie adresu URL i ponowne zapisywanie adresów URL

Różnica w sformułowaniu między przekierowywaniem adresów URL a ponownym zapisywaniem adresów URL jest subtelna, ale ma ważne konsekwencje dla udostępniania zasobów klientom. ASP.NET Core adres URL ponownego zapisywania oprogramowania pośredniczącego jest w stanie sprostać potrzebom obu tych programów.

Przekierowanie adresu URL obejmuje operację po stronie klienta, gdzie klient jest poinstruowany, aby uzyskać dostęp do zasobu pod innym adresem niż klient pierwotnie zażądał. Wymaga to rundy na serwerze. Adres URL przekierowania zwrócony do klienta jest wyświetlany na pasku adresu przeglądarki, gdy klient wysyła nowe żądanie dla zasobu.

Jeśli /resource nastąpi przekierowanie do /different-resourceusługi , serwer odpowiada, że klient powinien uzyskać zasób /different-resource z kodem stanu wskazującym, że przekierowanie jest tymczasowe lub trwałe.

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.

Podczas przekierowywania żądań do innego adresu URL wskaż, czy przekierowanie jest trwałe, czy tymczasowe, określając kod stanu z odpowiedzią:

  • Kod 301 - Moved Permanently stanu jest używany, gdy zasób ma nowy, trwały adres URL i chcesz poinstruować klienta, że wszystkie przyszłe żądania zasobu powinny używać nowego adresu URL. Klient może buforowania i ponownego użycia odpowiedzi po odebraniu kodu stanu 301.

  • Kod stanu 302 — Znaleziono jest używany, gdy przekierowanie jest tymczasowe lub zwykle może ulec zmianie. Kod stanu 302 wskazuje klientowi, aby nie przechowywał adresu URL i używał go w przyszłości.

Aby uzyskać więcej informacji na temat kodów stanu, zobacz RFC 9110: Definicje kodu stanu.

Ponowne zapisywanie adresu URL to operacja po stronie serwera, która udostępnia zasób z innego adresu zasobu niż żądany przez klienta. Ponowne zapisywanie adresu URL nie wymaga rundy na serwerze. Przepisany adres URL nie jest zwracany do klienta i nie jest wyświetlany na pasku adresu przeglądarki.

Jeśli /resource element zostanie przepisany do /different-resourceelementu , serwer wewnętrznie pobiera i zwraca zasób pod adresem /different-resource.

Mimo że klient może być w stanie pobrać zasób pod adresem URL przepisanego, klient nie jest informowany, że zasób istnieje pod adresem URL przepisanym, gdy wysyła żądanie i odbiera odpowiedź.

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.

Ponowne zapisywanie adresów URL przykładowej aplikacji

Możesz eksplorować funkcje oprogramowania pośredniczącego ponownego zapisywania adresów URL za pomocą przykładowej aplikacji. Aplikacja stosuje reguły przekierowania i ponownego zapisywania oraz wyświetla przekierowany lub przepisany adres URL w kilku scenariuszach.

Kiedy należy używać oprogramowania pośredniczącego ponownego zapisywania adresów URL

Użyj oprogramowania pośredniczącego ponownego zapisywania adresów URL, gdy nie możesz użyć następujących metod:

Użyj adresu URL ponownego zapisywania oprogramowania pośredniczącego, gdy aplikacja jest hostowana na serwerze HTTP.sys.

Główne przyczyny używania technologii ponownego zapisywania adresów URL opartych na serwerze w usługach IIS, Apache i Nginx są następujące:

  • Oprogramowanie pośredniczące nie obsługuje pełnych funkcji tych modułów.

    Niektóre funkcje modułów serwera nie działają z projektami ASP.NET Core, takimi jak IsFile i IsDirectory ograniczenia modułu ponownego zapisywania usług IIS. W tych scenariuszach należy zamiast tego użyć oprogramowania pośredniczącego.

  • Wydajność oprogramowania pośredniczącego prawdopodobnie nie jest zgodna z wydajnością modułów.

    Benchmarking to jedyny sposób, aby wiedzieć, które podejście obniża wydajność najbardziej lub jeśli wydajność obniżona jest nieznaczna.

Pakiet

Oprogramowanie pośredniczące ponownego zapisywania adresów URL jest dostarczane przez pakiet Microsoft.AspNetCore.Rewrite , który jest niejawnie uwzględniony w aplikacjach ASP.NET Core.

Rozszerzenia i opcje

Ustanów reguły ponownego zapisywania adresów URL i przekierowywania, tworząc wystąpienie klasy RewriteOptions przy użyciu metod rozszerzeń dla każdej reguły ponownego zapisywania. Łączenie wielu reguł w kolejności, w której mają być przetwarzane. Element RewriteOptions jest przekazywany do adresu URL Ponowne zapisywanie oprogramowania pośredniczącego, ponieważ jest on dodawany do potoku żądania za pomocą polecenia UseRewriter:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

Przekieruj nie-www na www

Trzy opcje umożliwiają aplikacji przekierowywanie żądań niezwiązanychwww z żądaniami do www:

Przekierowywanie adresów URL

Służy AddRedirect do przekierowywania żądań. Pierwszy parametr zawiera wyrażenie regularne do dopasowywania na ścieżce przychodzącego adresu URL. Drugi parametr to ciąg zastępczy. Trzeci parametr, jeśli jest obecny, określa kod stanu. Jeśli nie określisz kodu stanu, kod stanu jest domyślnie ustawiony na 302 — Znaleziono, co oznacza, że zasób jest tymczasowo przenoszony lub zastępowany.

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

W przeglądarce z włączonymi narzędziami deweloperskich prześlij żądanie do przykładowej aplikacji ze ścieżką /redirect-rule/1234/5678. Wyrażenie regularne pasuje do ścieżki żądania w pliku redirect-rule/(.*), a ścieżka jest zastępowana ciągiem /redirected/1234/5678. Adres URL przekierowania jest wysyłany z powrotem do klienta z kodem stanu 302 — Znaleziono . Przeglądarka wysyła nowe żądanie pod adresem URL przekierowania, które jest wyświetlane na pasku adresu przeglądarki. Ponieważ w adresie URL przekierowania nie są zgodne żadne reguły w przykładowej aplikacji:

  • Drugie żądanie odbiera odpowiedź 200 — OK z aplikacji.
  • Treść odpowiedzi zawiera adres URL przekierowania.

Podczas przekierowywania adresu URL następuje zaokrąglenie do serwera.

Ostrzeżenie

Podczas ustanawiania reguł przekierowania należy zachować ostrożność. Reguły przekierowania są oceniane dla każdego żądania do aplikacji, w tym po przekierowaniu. Łatwo jest przypadkowo utworzyć pętlę nieskończonych przekierowań.

Oryginalne żądanie: /redirect-rule/1234/5678

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

Część wyrażenia zawartego w nawiasach jest nazywana grupą przechwytywania. Kropka (.) wyrażenia oznacza dopasowanie dowolnego znaku. Gwiazdka (*) wskazuje dopasowanie poprzedniego znaku zero lub więcej razy. W związku z tym ostatnie dwa segmenty ścieżki adresu URL są 1234/5678przechwytywane przez grupę (.*)przechwytywania . Każda wartość, którą podajesz w adresie URL żądania po redirect-rule/ przechwyceniu przez tę pojedynczą grupę przechwytywania.

W ciągu zastępczym przechwycone grupy są wstrzykiwane do ciągu znakiem dolara ($), a następnie numerem sekwencji przechwytywania. Pierwsza wartość grupy przechwytywania jest uzyskiwana za pomocą $1elementu , drugiego z elementami $2i są one kontynuowane w sekwencji dla grup przechwytywania w regex. W przykładowej aplikacji istnieje tylko jedna przechwycona grupa w regex reguły przekierowania, więc w ciągu zastępczym znajduje się tylko jedna grupa wstrzyknięta, czyli $1. Po zastosowaniu reguły adres URL zmieni się na /redirected/1234/5678.

Przekierowanie adresu URL do bezpiecznego punktu końcowego

Użyj polecenia AddRedirectToHttps , aby przekierować żądania HTTP do tego samego hosta i ścieżki przy użyciu protokołu HTTPS. Jeśli kod stanu nie zostanie podany, oprogramowanie pośredniczące domyślnie ma wartość 302 — Znaleziono. Jeśli port nie jest podany:

  • Domyślnie oprogramowanie pośredniczące ma wartość null.
  • Schemat zmienia się na https (protokół HTTPS), a klient uzyskuje dostęp do zasobu na porcie 443.

W poniższym przykładzie pokazano, jak ustawić kod stanu na 301 - Moved Permanently i zmienić port na 5001.

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

    app.UseRewriter(options);
}

Służy AddRedirectToHttpsPermanent do przekierowywania niezabezpieczonych żądań do tego samego hosta i ścieżki przy użyciu bezpiecznego protokołu HTTPS na porcie 443. Oprogramowanie pośredniczące ustawia kod stanu na 301 - Moved Permanently.

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

    app.UseRewriter(options);
}

Uwaga

Podczas przekierowywania do bezpiecznego punktu końcowego bez wymagania dodatkowych reguł przekierowania zalecamy użycie oprogramowania pośredniczącego przekierowania HTTPS. Aby uzyskać więcej informacji, zobacz temat Wymuszanie protokołu HTTPS .

Przykładowa aplikacja może pokazać, jak używać AddRedirectToHttps metody lub AddRedirectToHttpsPermanent. Dodaj metodę rozszerzenia do klasy RewriteOptions. Utwórz niezabezpieczone żądanie do aplikacji pod dowolnym adresem URL. Odrzuć ostrzeżenie o zabezpieczeniach przeglądarki, że certyfikat z podpisem własnym jest niezaufany lub utwórz wyjątek, aby ufać certyfikatowi.

Oryginalne żądanie przy użyciu polecenia AddRedirectToHttps(301, 5001): http://localhost:5000/secure

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

Oryginalne żądanie przy użyciu polecenia AddRedirectToHttpsPermanent: http://localhost:5000/secure

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

Regenerowanie adresów URL

Użyj AddRewrite polecenia , aby utworzyć regułę na potrzeby ponownego zapisywania adresów URL. Pierwszy parametr zawiera wyrażenie regularne do dopasowywania w przychodzącej ścieżce adresu URL. Drugi parametr to ciąg zastępczy. Trzeci parametr , wskazuje oprogramowanie pośredniczące, skipRemainingRules: {true|false}czy pominąć dodatkowe reguły ponownego zapisywania, jeśli jest stosowana bieżąca reguła.

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

Oryginalne żądanie: /rewrite-rule/1234/5678

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

Karat (^) na początku wyrażenia oznacza, że dopasowanie rozpoczyna się na początku ścieżki adresu URL.

We wcześniejszym przykładzie z regułą redirect-rule/(.*)przekierowania nie ma karata (^) na początku regexu. W związku z tym wszelkie znaki mogą poprzedzać redirect-rule/ ścieżkę pomyślnego dopasowania.

Ścieżka Match
/redirect-rule/1234/5678 Tak
/my-cool-redirect-rule/1234/5678 Tak
/anotherredirect-rule/1234/5678 Tak

Reguła ponownego zapisywania, ^rewrite-rule/(\d+)/(\d+), pasuje tylko do ścieżek, jeśli zaczynają się od rewrite-rule/. W poniższej tabeli zwróć uwagę na różnicę w dopasowywaniu.

Ścieżka Match
/rewrite-rule/1234/5678 Tak
/my-cool-rewrite-rule/1234/5678 Nie.
/anotherrewrite-rule/1234/5678 Nie.

^rewrite-rule/ Po części wyrażenia istnieją dwie grupy przechwytywania: (\d+)/(\d+). Oznacza \d to dopasowanie cyfry (liczby). Znak plus (+) oznacza dopasowanie co najmniej jednego z powyższych znaków. W związku z tym adres URL musi zawierać liczbę, po której następuje ukośnik do przodu, po którym następuje kolejna liczba. Te grupy przechwytywania są wstrzykiwane do przepisanego adresu URL jako $1 i $2. Ciąg zastępczy reguły ponownej zapisywania umieszcza przechwycone grupy w ciągu zapytania. Żądana ścieżka elementu /rewrite-rule/1234/5678 zostanie przepisana, aby uzyskać zasób pod adresem /rewritten?var1=1234&var2=5678. Jeśli ciąg zapytania jest obecny w oryginalnym żądaniu, zostanie on zachowany, gdy adres URL zostanie przepisany.

Nie ma rundy na serwerze, aby uzyskać zasób. Jeśli zasób istnieje, jest pobierany i zwracany do klienta z kodem stanu 200 — OK . Ponieważ klient nie jest przekierowywany, adres URL na pasku adresu przeglądarki nie zmienia się. Klienci nie mogą wykryć, że na serwerze wystąpiła operacja ponownego zapisywania adresu URL.

Uwaga

Używaj skipRemainingRules: true zawsze, gdy jest to możliwe, ponieważ pasujące reguły są kosztowne w obliczeniach i zwiększają czas odpowiedzi aplikacji. Aby uzyskać najszybszą odpowiedź na aplikację:

  • Kolejność ponownego zapisywania reguł z najczęściej dopasowywanej reguły do najmniej często dopasowywanej reguły.
  • Pomiń przetwarzanie pozostałych reguł, gdy wystąpi dopasowanie i nie jest wymagane żadne dodatkowe przetwarzanie reguł.

Apache mod_rewrite

Zastosuj reguły usługi Apache mod_rewrite za pomocą polecenia AddApacheModRewrite. Upewnij się, że plik reguł został wdrożony z aplikacją. Aby uzyskać więcej informacji i przykłady reguł mod_rewrite, zobacz Apache mod_rewrite.

Element służy StreamReader do odczytywania reguł z pliku reguł ApacheModRewrite.txt :

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

Przykładowa aplikacja przekierowuje żądania z /apache-mod-rules-redirect/(.\*) do /redirected?id=$1. Kod stanu odpowiedzi to 302 — Znaleziono.

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

Oryginalne żądanie: /apache-mod-rules-redirect/1234

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

Oprogramowanie pośredniczące obsługuje następujące zmienne serwera Apache mod_rewrite:

  • CONN_REMOTE_ADDR
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_FORWARDED
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_USER_AGENT
  • HTTPS
  • Protokół 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

Reguły ponownego zapisywania modułów adresów URL usług IIS

Aby użyć tego samego zestawu reguł, który ma zastosowanie do modułu ponownego zapisywania adresów URL usług IIS, użyj polecenia AddIISUrlRewrite. Upewnij się, że plik reguł został wdrożony z aplikacją. Nie należy kierować oprogramowania pośredniczącego do używania pliku web.config aplikacji podczas uruchamiania w usługach IIS systemu Windows Server. W przypadku usług IIS te reguły powinny być przechowywane poza plikiem web.config aplikacji, aby uniknąć konfliktów z modułem Ponowne zapisywanie usług IIS. Aby uzyskać więcej informacji i przykłady reguł modułu ponownego zapisywania adresów URL usług IIS, zobacz Using Url Rewrite Module 2.0 and URL Rewrite Module Configuration Reference (Używanie modułu ponownego zapisywania adresów URL w wersji 2.0 ) i URL Rewrite Module Reference (Dokumentacja konfiguracji modułu ponownego zapisywania adresów URL).

Element A StreamReader służy do odczytywania reguł z IISUrlRewrite.xml pliku reguł:

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

Przykładowa aplikacja ponownie zapisuje żądania z /iis-rules-rewrite/(.*) do /rewritten?id=$1. Odpowiedź jest wysyłana do klienta z kodem stanu 200 — OK .

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

Oryginalne żądanie: /iis-rules-rewrite/1234

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

Jeśli masz aktywny moduł ponownego zapisywania usług IIS z skonfigurowanymi regułami na poziomie serwera, które będą miały wpływ na aplikację w niepożądany sposób, możesz wyłączyć moduł ponownego zapisywania usług IIS dla aplikacji. Aby uzyskać więcej informacji, zobacz Wyłączanie modułów usług IIS.

Nieobsługiwane funkcje

Oprogramowanie pośredniczące nie obsługuje następujących funkcji modułu ponownego zapisywania adresów URL usług IIS:

  • Reguły ruchu wychodzącego
  • Niestandardowe zmienne serwera
  • Symbole wieloznaczne
  • LogRewrittenUrl

Obsługiwane zmienne serwera

Oprogramowanie pośredniczące obsługuje następujące zmienne serwera modułu ponownego zapisywania adresów URL usług IIS:

  • 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

Uwaga

Możesz również uzyskać element IFileProvider za pośrednictwem elementu PhysicalFileProvider. Takie podejście może zapewnić większą elastyczność lokalizacji plików reguł ponownego zapisywania. Upewnij się, że pliki reguł ponownego zapisywania są wdrażane na serwerze w podanej ścieżce.

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

Reguła oparta na metodzie

Użyj Add polecenia , aby zaimplementować własną logikę reguł w metodzie . Add uwidacznia element RewriteContext, który udostępnia HttpContext element do użycia w metodzie . RewriteContext.Result określa sposób obsługi dodatkowego przetwarzania potoku. Ustaw wartość na jedno z RuleResult pól opisanych w poniższej tabeli.

Wynik ponownego zapisywania kontekstu Akcja
RuleResult.ContinueRules (domyślne) Kontynuuj stosowanie reguł.
RuleResult.EndResponse Przestań stosować reguły i wysyłać odpowiedź.
RuleResult.SkipRemainingRules Przestań stosować reguły i wysyłać kontekst do następnego oprogramowania pośredniczącego.
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}"));
}

Przykładowa aplikacja demonstruje metodę, która przekierowuje żądania dla ścieżek zakończonych ciągiem .xml. Jeśli żądanie zostanie wykonane dla /file.xmlelementu , żądanie zostanie przekierowane do /xmlfiles/file.xml. Kod stanu jest ustawiony na 301 - Moved Permanentlywartość . Gdy przeglądarka wysyła nowe żądanie dla /xmlfiles/file.xmlprogramu , oprogramowanie pośredniczące plików statycznych udostępnia klientowi plik z folderu wwwroot/xmlfiles . W przypadku przekierowania jawnie ustaw kod stanu odpowiedzi. W przeciwnym razie zwracany jest kod stanu 200 — OK, a przekierowanie nie występuje na kliencie.

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

Takie podejście może również ponownie pisać żądania. Przykładowa aplikacja demonstruje ponowne zapisywanie ścieżki dla dowolnego żądania pliku tekstowego w celu obsłużenia pliku tekstowego file.txt z folderu wwwroot. Oprogramowanie pośredniczące plików statycznych obsługuje plik na podstawie zaktualizowanej ścieżki żądania:

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

Reguła oparta na protokole IRule

Służy Add do używania logiki reguł w klasie, która implementuje IRule interfejs. IRule zapewnia większą elastyczność przy użyciu podejścia opartego na metodzie. Klasa implementacji może zawierać konstruktor, który umożliwia przekazywanie parametrów dla ApplyRule metody .

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

Wartości parametrów w przykładowej aplikacji dla extension elementu i newPath są sprawdzane pod kątem spełnienia kilku warunków. Wartość extension musi zawierać wartość, a wartość musi mieć .pngwartość , .jpglub .gif. Jeśli element newPath jest nieprawidłowy, zostanie zgłoszony element ArgumentException . Jeśli żądanie zostanie wykonane dla image.pngelementu , żądanie zostanie przekierowane do /png-images/image.png. Jeśli żądanie zostanie wykonane dla image.jpgelementu , żądanie zostanie przekierowane do /jpg-images/image.jpg. Kod stanu jest ustawiony na 301 - Moved Permanentlywartość , a context.Result właściwość jest ustawiona na wartość , aby zatrzymać przetwarzanie reguł i wysłać odpowiedź.

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

Oryginalne żądanie: /image.png

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

Oryginalne żądanie: /image.jpg

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

Przykłady wyrażeń regularnych

Goal Ciąg wyrażeń regularnych i
Przykład dopasowania
Ciąg zastępczy i
Przykład danych wyjściowych
Ponowne zapisywanie ścieżki do elementu querystring ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Pasek końcowy ukośnik (.*)/$
/path/
$1
/path
Wymuszanie ukośnika końcowego (.*[^/])$
/path
$1/
/path/
Unikaj ponownego zapisywania określonych żądań ^(.*)(?<!\.axd)$ lub ^(?!.*\.axd$)(.*)$
Tak: /resource.htm
Nr: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Ponowne rozmieszczanie segmentów adresów URL path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Zastępowanie segmentu adresu URL ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

W tym dokumencie przedstawiono ponowne zapisywanie adresów URL z instrukcjami dotyczącymi używania oprogramowania pośredniczącego ponownego zapisywania adresów URL w aplikacjach ASP.NET Core.

Ponowne zapisywanie adresów URL to czynność modyfikowania adresów URL żądań na podstawie co najmniej jednej wstępnie zdefiniowanej reguły. Ponowne zapisywanie adresów URL powoduje utworzenie abstrakcji między lokalizacjami zasobów a ich adresami, dzięki czemu lokalizacje i adresy nie są ściśle połączone. Ponowne zapisywanie adresów URL jest przydatne w kilku scenariuszach:

  • Tymczasowe lub trwałe przenoszenie lub zastępowanie zasobów serwera i utrzymywanie stabilnych lokalizatorów dla tych zasobów.
  • Podziel przetwarzanie żądań między różne aplikacje lub obszary jednej aplikacji.
  • Usuwanie, dodawanie lub reorganizacja segmentów adresów URL dla żądań przychodzących.
  • Optymalizowanie publicznych adresów URL na potrzeby optymalizacji aparatu wyszukiwania (SEO).
  • Zezwól na używanie przyjaznych publicznych adresów URL, aby ułatwić odwiedzającym przewidywanie zawartości zwracanej przez żądanie zasobu.
  • Przekieruj niezabezpieczone żądania do bezpiecznych punktów końcowych.
  • Zapobiegaj łączeniu gorąca, w którym witryna zewnętrzna używa hostowanego zasobu statycznego w innej witrynie, łącząc zasób z własną zawartością.

Uwaga

Ponowne zapisywanie adresów URL może zmniejszyć wydajność aplikacji. W miarę możliwości ogranicz liczbę i złożoność reguł.

Wyświetl lub pobierz przykładowy kod (jak pobrać)

Przekierowanie adresu URL i ponowne zapisywanie adresów URL

Różnica w sformułowaniu między przekierowywaniem adresów URL a ponownym zapisywaniem adresów URL jest subtelna, ale ma ważne konsekwencje dla udostępniania zasobów klientom. ASP.NET Core adres URL ponownego zapisywania oprogramowania pośredniczącego jest w stanie sprostać potrzebom obu tych programów.

Przekierowanie adresu URL obejmuje operację po stronie klienta, gdzie klient jest poinstruowany, aby uzyskać dostęp do zasobu pod innym adresem niż klient pierwotnie zażądał. Wymaga to rundy na serwerze. Adres URL przekierowania zwrócony do klienta jest wyświetlany na pasku adresu przeglądarki, gdy klient wysyła nowe żądanie dla zasobu.

Jeśli /resource nastąpi przekierowanie do /different-resourceusługi , serwer odpowiada, że klient powinien uzyskać zasób /different-resource z kodem stanu wskazującym, że przekierowanie jest tymczasowe lub trwałe.

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.

Podczas przekierowywania żądań do innego adresu URL wskaż, czy przekierowanie jest trwałe, czy tymczasowe, określając kod stanu z odpowiedzią:

  • Kod 301 - Moved Permanently stanu jest używany, gdy zasób ma nowy, trwały adres URL i chcesz poinstruować klienta, że wszystkie przyszłe żądania zasobu powinny używać nowego adresu URL. Klient może buforowania i ponownego użycia odpowiedzi po odebraniu kodu stanu 301.

  • Kod stanu 302 — Znaleziono jest używany, gdy przekierowanie jest tymczasowe lub zwykle może ulec zmianie. Kod stanu 302 wskazuje klientowi, aby nie przechowywał adresu URL i używał go w przyszłości.

Aby uzyskać więcej informacji na temat kodów stanu, zobacz RFC 9110: Definicje kodu stanu.

Ponowne zapisywanie adresu URL to operacja po stronie serwera, która udostępnia zasób z innego adresu zasobu niż żądany przez klienta. Ponowne zapisywanie adresu URL nie wymaga rundy na serwerze. Przepisany adres URL nie jest zwracany do klienta i nie jest wyświetlany na pasku adresu przeglądarki.

Jeśli /resource element zostanie przepisany do /different-resourceelementu , serwer wewnętrznie pobiera i zwraca zasób pod adresem /different-resource.

Mimo że klient może być w stanie pobrać zasób pod adresem URL przepisanego, klient nie jest informowany, że zasób istnieje pod adresem URL przepisanym, gdy wysyła żądanie i odbiera odpowiedź.

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.

Ponowne zapisywanie adresów URL przykładowej aplikacji

Możesz eksplorować funkcje oprogramowania pośredniczącego ponownego zapisywania adresów URL za pomocą przykładowej aplikacji. Aplikacja stosuje reguły przekierowania i ponownego zapisywania oraz wyświetla przekierowany lub przepisany adres URL w kilku scenariuszach.

Kiedy należy używać oprogramowania pośredniczącego ponownego zapisywania adresów URL

Użyj oprogramowania pośredniczącego ponownego zapisywania adresów URL, gdy nie możesz użyć następujących metod:

Ponadto należy użyć oprogramowania pośredniczącego, gdy aplikacja jest hostowana na serwerze HTTP.sys (wcześniej nazywanym WebListener).

Główne przyczyny używania technologii ponownego zapisywania adresów URL opartych na serwerze w usługach IIS, Apache i Nginx są następujące:

  • Oprogramowanie pośredniczące nie obsługuje pełnych funkcji tych modułów.

    Niektóre funkcje modułów serwera nie działają z projektami ASP.NET Core, takimi jak IsFile i IsDirectory ograniczenia modułu ponownego zapisywania usług IIS. W tych scenariuszach należy zamiast tego użyć oprogramowania pośredniczącego.

  • Wydajność oprogramowania pośredniczącego prawdopodobnie nie jest zgodna z wydajnością modułów.

    Benchmarking to jedyny sposób, aby wiedzieć, które podejście obniża wydajność najbardziej lub jeśli wydajność obniżona jest nieznaczna.

Pakiet

Aby uwzględnić oprogramowanie pośredniczące w projekcie, dodaj odwołanie do pakietu Microsoft.AspNetCore.App metapakietu w pliku projektu, który zawiera pakiet Microsoft.AspNetCore.Rewrite .

Jeśli nie używasz Microsoft.AspNetCore.App metapakiet, dodaj odwołanie do projektu do Microsoft.AspNetCore.Rewrite pakietu.

Rozszerzenia i opcje

Ustanów reguły ponownego zapisywania adresów URL i przekierowywania, tworząc wystąpienie klasy RewriteOptions przy użyciu metod rozszerzeń dla każdej reguły ponownego zapisywania. Łączenie wielu reguł w kolejności, w której mają być przetwarzane. Element RewriteOptions jest przekazywany do adresu URL Ponowne zapisywanie oprogramowania pośredniczącego, ponieważ jest on dodawany do potoku żądania za pomocą polecenia UseRewriter:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

Przekieruj nie-www na www

Trzy opcje umożliwiają aplikacji przekierowywanie żądań niezwiązanychwww z żądaniami do www:

Przekierowywanie adresów URL

Służy AddRedirect do przekierowywania żądań. Pierwszy parametr zawiera wyrażenie regularne do dopasowywania na ścieżce przychodzącego adresu URL. Drugi parametr to ciąg zastępczy. Trzeci parametr, jeśli jest obecny, określa kod stanu. Jeśli nie określisz kodu stanu, kod stanu jest domyślnie ustawiony na 302 — Znaleziono, co oznacza, że zasób jest tymczasowo przenoszony lub zastępowany.

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

W przeglądarce z włączonymi narzędziami deweloperskich prześlij żądanie do przykładowej aplikacji ze ścieżką /redirect-rule/1234/5678. Wyrażenie regularne pasuje do ścieżki żądania w pliku redirect-rule/(.*), a ścieżka jest zastępowana ciągiem /redirected/1234/5678. Adres URL przekierowania jest wysyłany z powrotem do klienta z kodem stanu 302 — Znaleziono . Przeglądarka wysyła nowe żądanie pod adresem URL przekierowania, które jest wyświetlane na pasku adresu przeglądarki. Ponieważ w adresie URL przekierowania nie są zgodne żadne reguły w przykładowej aplikacji:

  • Drugie żądanie odbiera odpowiedź 200 — OK z aplikacji.
  • Treść odpowiedzi zawiera adres URL przekierowania.

Podczas przekierowywania adresu URL następuje zaokrąglenie do serwera.

Ostrzeżenie

Podczas ustanawiania reguł przekierowania należy zachować ostrożność. Reguły przekierowania są oceniane dla każdego żądania do aplikacji, w tym po przekierowaniu. Łatwo jest przypadkowo utworzyć pętlę nieskończonych przekierowań.

Oryginalne żądanie: /redirect-rule/1234/5678

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

Część wyrażenia zawartego w nawiasach jest nazywana grupą przechwytywania. Kropka (.) wyrażenia oznacza dopasowanie dowolnego znaku. Gwiazdka (*) wskazuje dopasowanie poprzedniego znaku zero lub więcej razy. W związku z tym ostatnie dwa segmenty ścieżki adresu URL są 1234/5678przechwytywane przez grupę (.*)przechwytywania . Każda wartość, którą podajesz w adresie URL żądania po redirect-rule/ przechwyceniu przez tę pojedynczą grupę przechwytywania.

W ciągu zastępczym przechwycone grupy są wstrzykiwane do ciągu znakiem dolara ($), a następnie numerem sekwencji przechwytywania. Pierwsza wartość grupy przechwytywania jest uzyskiwana za pomocą $1elementu , drugiego z elementami $2i są one kontynuowane w sekwencji dla grup przechwytywania w regex. W przykładowej aplikacji istnieje tylko jedna przechwycona grupa w regex reguły przekierowania, więc w ciągu zastępczym znajduje się tylko jedna grupa wstrzyknięta, czyli $1. Po zastosowaniu reguły adres URL zmieni się na /redirected/1234/5678.

Przekierowanie adresu URL do bezpiecznego punktu końcowego

Użyj polecenia AddRedirectToHttps , aby przekierować żądania HTTP do tego samego hosta i ścieżki przy użyciu protokołu HTTPS. Jeśli kod stanu nie zostanie podany, oprogramowanie pośredniczące domyślnie ma wartość 302 — Znaleziono. Jeśli port nie jest podany:

  • Domyślnie oprogramowanie pośredniczące ma wartość null.
  • Schemat zmienia się na https (protokół HTTPS), a klient uzyskuje dostęp do zasobu na porcie 443.

W poniższym przykładzie pokazano, jak ustawić kod stanu na 301 - Moved Permanently i zmienić port na 5001.

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

    app.UseRewriter(options);
}

Służy AddRedirectToHttpsPermanent do przekierowywania niezabezpieczonych żądań do tego samego hosta i ścieżki przy użyciu bezpiecznego protokołu HTTPS na porcie 443. Oprogramowanie pośredniczące ustawia kod stanu na 301 - Moved Permanently.

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

    app.UseRewriter(options);
}

Uwaga

Podczas przekierowywania do bezpiecznego punktu końcowego bez wymagania dodatkowych reguł przekierowania zalecamy użycie oprogramowania pośredniczącego przekierowania HTTPS. Aby uzyskać więcej informacji, zobacz temat Wymuszanie protokołu HTTPS .

Przykładowa aplikacja może pokazać, jak używać AddRedirectToHttps metody lub AddRedirectToHttpsPermanent. Dodaj metodę rozszerzenia do klasy RewriteOptions. Utwórz niezabezpieczone żądanie do aplikacji pod dowolnym adresem URL. Odrzuć ostrzeżenie o zabezpieczeniach przeglądarki, że certyfikat z podpisem własnym jest niezaufany lub utwórz wyjątek, aby ufać certyfikatowi.

Oryginalne żądanie przy użyciu polecenia AddRedirectToHttps(301, 5001): http://localhost:5000/secure

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

Oryginalne żądanie przy użyciu polecenia AddRedirectToHttpsPermanent: http://localhost:5000/secure

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

Regenerowanie adresów URL

Użyj AddRewrite polecenia , aby utworzyć regułę na potrzeby ponownego zapisywania adresów URL. Pierwszy parametr zawiera wyrażenie regularne do dopasowywania w przychodzącej ścieżce adresu URL. Drugi parametr to ciąg zastępczy. Trzeci parametr , wskazuje oprogramowanie pośredniczące, skipRemainingRules: {true|false}czy pominąć dodatkowe reguły ponownego zapisywania, jeśli jest stosowana bieżąca reguła.

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

Oryginalne żądanie: /rewrite-rule/1234/5678

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

Karat (^) na początku wyrażenia oznacza, że dopasowanie rozpoczyna się na początku ścieżki adresu URL.

We wcześniejszym przykładzie z regułą redirect-rule/(.*)przekierowania nie ma karata (^) na początku regexu. W związku z tym wszelkie znaki mogą poprzedzać redirect-rule/ ścieżkę pomyślnego dopasowania.

Ścieżka Match
/redirect-rule/1234/5678 Tak
/my-cool-redirect-rule/1234/5678 Tak
/anotherredirect-rule/1234/5678 Tak

Reguła ponownego zapisywania, ^rewrite-rule/(\d+)/(\d+), pasuje tylko do ścieżek, jeśli zaczynają się od rewrite-rule/. W poniższej tabeli zwróć uwagę na różnicę w dopasowywaniu.

Ścieżka Match
/rewrite-rule/1234/5678 Tak
/my-cool-rewrite-rule/1234/5678 Nie.
/anotherrewrite-rule/1234/5678 Nie.

^rewrite-rule/ Po części wyrażenia istnieją dwie grupy przechwytywania: (\d+)/(\d+). Oznacza \d to dopasowanie cyfry (liczby). Znak plus (+) oznacza dopasowanie co najmniej jednego z powyższych znaków. W związku z tym adres URL musi zawierać liczbę, po której następuje ukośnik do przodu, po którym następuje kolejna liczba. Te grupy przechwytywania są wstrzykiwane do przepisanego adresu URL jako $1 i $2. Ciąg zastępczy reguły ponownej zapisywania umieszcza przechwycone grupy w ciągu zapytania. Żądana ścieżka elementu /rewrite-rule/1234/5678 zostanie przepisana, aby uzyskać zasób pod adresem /rewritten?var1=1234&var2=5678. Jeśli ciąg zapytania jest obecny w oryginalnym żądaniu, zostanie on zachowany, gdy adres URL zostanie przepisany.

Nie ma rundy na serwerze, aby uzyskać zasób. Jeśli zasób istnieje, jest pobierany i zwracany do klienta z kodem stanu 200 — OK . Ponieważ klient nie jest przekierowywany, adres URL na pasku adresu przeglądarki nie zmienia się. Klienci nie mogą wykryć, że na serwerze wystąpiła operacja ponownego zapisywania adresu URL.

Uwaga

Używaj skipRemainingRules: true zawsze, gdy jest to możliwe, ponieważ pasujące reguły są kosztowne w obliczeniach i zwiększają czas odpowiedzi aplikacji. Aby uzyskać najszybszą odpowiedź na aplikację:

  • Kolejność ponownego zapisywania reguł z najczęściej dopasowywanej reguły do najmniej często dopasowywanej reguły.
  • Pomiń przetwarzanie pozostałych reguł, gdy wystąpi dopasowanie i nie jest wymagane żadne dodatkowe przetwarzanie reguł.

Apache mod_rewrite

Zastosuj reguły usługi Apache mod_rewrite za pomocą polecenia AddApacheModRewrite. Upewnij się, że plik reguł został wdrożony z aplikacją. Aby uzyskać więcej informacji i przykłady reguł mod_rewrite, zobacz Apache mod_rewrite.

Element służy StreamReader do odczytywania reguł z pliku reguł ApacheModRewrite.txt :

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

Przykładowa aplikacja przekierowuje żądania z /apache-mod-rules-redirect/(.\*) do /redirected?id=$1. Kod stanu odpowiedzi to 302 — Znaleziono.

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

Oryginalne żądanie: /apache-mod-rules-redirect/1234

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

Oprogramowanie pośredniczące obsługuje następujące zmienne serwera Apache mod_rewrite:

  • CONN_REMOTE_ADDR
  • HTTP_ACCEPT
  • HTTP_CONNECTION
  • HTTP_COOKIE
  • HTTP_FORWARDED
  • HTTP_HOST
  • HTTP_REFERER
  • HTTP_USER_AGENT
  • HTTPS
  • Protokół 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

Reguły ponownego zapisywania modułów adresów URL usług IIS

Aby użyć tego samego zestawu reguł, który ma zastosowanie do modułu ponownego zapisywania adresów URL usług IIS, użyj polecenia AddIISUrlRewrite. Upewnij się, że plik reguł został wdrożony z aplikacją. Nie należy kierować oprogramowania pośredniczącego do używania pliku web.config aplikacji podczas uruchamiania w usługach IIS systemu Windows Server. W przypadku usług IIS te reguły powinny być przechowywane poza plikiem web.config aplikacji, aby uniknąć konfliktów z modułem Ponowne zapisywanie usług IIS. Aby uzyskać więcej informacji i przykłady reguł modułu ponownego zapisywania adresów URL usług IIS, zobacz Using Url Rewrite Module 2.0 and URL Rewrite Module Configuration Reference (Używanie modułu ponownego zapisywania adresów URL w wersji 2.0 ) i URL Rewrite Module Reference (Dokumentacja konfiguracji modułu ponownego zapisywania adresów URL).

Element A StreamReader służy do odczytywania reguł z IISUrlRewrite.xml pliku reguł:

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

Przykładowa aplikacja ponownie zapisuje żądania z /iis-rules-rewrite/(.*) do /rewritten?id=$1. Odpowiedź jest wysyłana do klienta z kodem stanu 200 — OK .

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

Oryginalne żądanie: /iis-rules-rewrite/1234

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

Jeśli masz aktywny moduł ponownego zapisywania usług IIS z skonfigurowanymi regułami na poziomie serwera, które będą miały wpływ na aplikację w niepożądany sposób, możesz wyłączyć moduł ponownego zapisywania usług IIS dla aplikacji. Aby uzyskać więcej informacji, zobacz Wyłączanie modułów usług IIS.

Nieobsługiwane funkcje

Oprogramowanie pośredniczące wydane za pomocą ASP.NET Core 2.x nie obsługuje następujących funkcji modułu ponownego zapisywania adresów URL usług IIS:

  • Reguły ruchu wychodzącego
  • Niestandardowe zmienne serwera
  • Symbole wieloznaczne
  • LogRewrittenUrl

Obsługiwane zmienne serwera

Oprogramowanie pośredniczące obsługuje następujące zmienne serwera modułu ponownego zapisywania adresów URL usług IIS:

  • 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

Uwaga

Możesz również uzyskać element IFileProvider za pośrednictwem elementu PhysicalFileProvider. Takie podejście może zapewnić większą elastyczność lokalizacji plików reguł ponownego zapisywania. Upewnij się, że pliki reguł ponownego zapisywania są wdrażane na serwerze w podanej ścieżce.

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

Reguła oparta na metodzie

Użyj Add polecenia , aby zaimplementować własną logikę reguł w metodzie . Add uwidacznia element RewriteContext, który udostępnia HttpContext element do użycia w metodzie . RewriteContext.Result określa sposób obsługi dodatkowego przetwarzania potoku. Ustaw wartość na jedno z RuleResult pól opisanych w poniższej tabeli.

Wynik ponownego zapisywania kontekstu Akcja
RuleResult.ContinueRules (domyślne) Kontynuuj stosowanie reguł.
RuleResult.EndResponse Przestań stosować reguły i wysyłać odpowiedź.
RuleResult.SkipRemainingRules Przestań stosować reguły i wysyłać kontekst do następnego oprogramowania pośredniczącego.
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}"));
}

Przykładowa aplikacja demonstruje metodę, która przekierowuje żądania dla ścieżek zakończonych ciągiem .xml. Jeśli żądanie zostanie wykonane dla /file.xmlelementu , żądanie zostanie przekierowane do /xmlfiles/file.xml. Kod stanu jest ustawiony na 301 - Moved Permanentlywartość . Gdy przeglądarka wysyła nowe żądanie dla /xmlfiles/file.xmlprogramu , oprogramowanie pośredniczące plików statycznych udostępnia klientowi plik z folderu wwwroot/xmlfiles . W przypadku przekierowania jawnie ustaw kod stanu odpowiedzi. W przeciwnym razie zwracany jest kod stanu 200 — OK, a przekierowanie nie występuje na kliencie.

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

Takie podejście może również ponownie pisać żądania. Przykładowa aplikacja demonstruje ponowne zapisywanie ścieżki dla dowolnego żądania pliku tekstowego w celu obsłużenia pliku tekstowego file.txt z folderu wwwroot. Oprogramowanie pośredniczące plików statycznych obsługuje plik na podstawie zaktualizowanej ścieżki żądania:

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

Reguła oparta na protokole IRule

Służy Add do używania logiki reguł w klasie, która implementuje IRule interfejs. IRule zapewnia większą elastyczność przy użyciu podejścia opartego na metodzie. Klasa implementacji może zawierać konstruktor, który umożliwia przekazywanie parametrów dla ApplyRule metody .

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

Wartości parametrów w przykładowej aplikacji dla extension elementu i newPath są sprawdzane pod kątem spełnienia kilku warunków. Wartość extension musi zawierać wartość, a wartość musi mieć .pngwartość , .jpglub .gif. Jeśli element newPath jest nieprawidłowy, zostanie zgłoszony element ArgumentException . Jeśli żądanie zostanie wykonane dla image.pngelementu , żądanie zostanie przekierowane do /png-images/image.png. Jeśli żądanie zostanie wykonane dla image.jpgelementu , żądanie zostanie przekierowane do /jpg-images/image.jpg. Kod stanu jest ustawiony na 301 - Moved Permanentlywartość , a context.Result właściwość jest ustawiona na wartość , aby zatrzymać przetwarzanie reguł i wysłać odpowiedź.

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

Oryginalne żądanie: /image.png

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

Oryginalne żądanie: /image.jpg

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

Przykłady wyrażeń regularnych

Goal Ciąg wyrażeń regularnych i
Przykład dopasowania
Ciąg zastępczy i
Przykład danych wyjściowych
Ponowne zapisywanie ścieżki do elementu querystring ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Pasek końcowy ukośnik (.*)/$
/path/
$1
/path
Wymuszanie ukośnika końcowego (.*[^/])$
/path
$1/
/path/
Unikaj ponownego zapisywania określonych żądań ^(.*)(?<!\.axd)$ lub ^(?!.*\.axd$)(.*)$
Tak: /resource.htm
Nr: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Ponowne rozmieszczanie segmentów adresów URL path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Zastępowanie segmentu adresu URL ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

Dodatkowe zasoby