Middleware Riscrittura URL in ASP.NET Core

Di Kirk Larkin e Rick Anderson

Questo articolo presenta la riscrittura degli URL con istruzioni su come usare il middleware di riscrittura URL nelle app di base ASP.NET.

La riscrittura URL è l'azione di modificare gli URL di richiesta in base a una o più regole predefinite. Il processo di riscrittura URL crea un'astrazione tra i percorsi delle risorse e i relativi indirizzi, in modo che i percorsi e gli indirizzi non risultino strettamente collegati. La riscrittura URL risulta utile in diversi scenari per:

  • Spostare o sostituire in modo temporaneo o permanente risorse server mantenendo localizzatori stabili di queste risorse.
  • Suddividere l'elaborazione delle richieste tra app diverse o tra aree diverse di un'unica app.
  • Rimuovere, aggiungere o riorganizzare segmenti URL nelle richieste in ingresso.
  • Ottimizzare gli URL pubblici per l'ottimizzazione motore di ricerca (SEO, Search Engine Optimization).
  • Consentire l'uso di URL pubblici descrittivi in modo che i visitatori possano prevedere il contenuto restituito dalla richiesta di una risorsa.
  • Reindirizzare le richieste non protette a endpoint protetti.
  • Evitare l'hotlinking, ovvero l'uso da parte di un sito esterno di una risorsa statica ospitata presente in un altro sito tramite il collegamento di questa al proprio contenuto.

La riscrittura degli URL può ridurre le prestazioni di un'app. Limitare il numero e la complessità delle regole.

Reindirizzamento URL e riscrittura URL

La differenza tra i termini reindirizzamento URL e riscrittura URL è minima, ma ha implicazioni importanti nell'offerta di risorse ai clienti. Il middleware Riscrittura URL di ASP.NET Core è in grado di svolgere entrambe le funzioni.

Un reindirizzamento URL implica un'operazione lato client, in cui viene richiesto al client di accedere a una risorsa a un indirizzo diverso da quello richiesto originariamente dal client. Questa operazione richiede un round trip al server. L'URL di reindirizzamento restituito al client viene visualizzato nella barra degli indirizzi del browser quando il client effettua una nuova richiesta per la risorsa.

In caso di reindirizzamento di /resource a /different-resource, il server risponde che il client deve ottenere la risorsa presso /different-resource con un codice di stato che indica se il reindirizzamento è temporaneo o permanente.

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

Quando si reindirizzano le richieste a un URL diverso, indicare se il reindirizzamento è temporaneo o permanente specificando il codice di stato con la risposta:

  • Il 301 - Moved Permanently codice di stato viene usato in cui la risorsa ha un nuovo URL permanente e che tutte le richieste future per la risorsa devono usare il nuovo URL. Quando riceve un codice di stato 301, il client può memorizzare la risposta nella cache e riusarla.

  • Il 302 - Found codice di stato viene usato in cui il reindirizzamento è temporaneo o generalmente soggetto a modifiche. Il codice di stato 302 indica che il client non dovrà archiviare e riusare l'URL di reindirizzamento in futuro.

Per altre informazioni sui codici di stato, vedere RFC 9110: Definizioni di codice di stato.

La riscrittura URL è un'operazione lato server che rende disponibile una risorsa da un indirizzo diverso da quello richiesto dal client. La riscrittura URL non richiede un round trip al server. L'URL riscritto non viene restituito al client e non viene visualizzato nella barra degli indirizzi del browser.

Se /resource viene riscritto in /different-resource, il server recupera internamente la risorsa in /different-resource.

Anche se il client fosse in grado di recuperare la risorsa nell'URL riscritto, non viene informato dell'esistenza della risorsa nell'URL riscritto quando effettua la richiesta e riceve la risposta.

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.

App di esempio per la riscrittura URL

Esplorare le funzionalità del middleware di riscrittura URL con l'app di esempio. L'app applica regole di reindirizzamento e riscrittura e visualizza l'URL reindirizzato o riscritto per diversi scenari.

Quando usare il middleware di riscrittura URL

Usare il middleware di riscrittura URL quando gli approcci seguenti non sono soddisfacenti:

Usare il middleware di riscrittura url quando l'app è ospitata nel server HTTP.sys.

I motivi principali per usare tecnologie di riscrittura URL basate su server in IIS, Apache e Nginx sono:

  • Il middleware non supporta tutte le funzionalità di questi moduli.

    Alcune funzionalità dei moduli server non funzionano con i progetti ASP.NET Core, ad esempio i vincoli IsFile e IsDirectory del modulo IIS Rewrite. In questi scenari è necessario usare il middleware.

  • Le prestazioni del middleware probabilmente non corrispondono a quelle dei moduli.

    Il benchmarking è l'unico modo per sapere con certezza quale approccio degrada le prestazioni al massimo o se le prestazioni ridotte sono trascurabili.

Estensioni e opzioni

Stabilire regole di riscrittura e reindirizzamento url creando un'istanza della classe RewriteOptions con metodi di estensione per ognuna delle regole di riscrittura. Concatenare più regole nell'ordine in cui devono essere elaborate. Le opzioni RewriteOptions vengono passate al middleware Riscrittura URL quando questo viene aggiunto alla pipeline della richiesta con 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();

Nel codice precedente è MethodRules una classe definita dall'utente. Per altre informazioni, vedere RewriteRules.cs in questo articolo.

Reindirizzare non-www su www

Sono disponibili tre opzioni che consentono all'app di reindirizzare richieste non-www su www:

Reindirizzamento URL

Per reindirizzare le richieste, usare AddRedirect. Il primo parametro contiene l'espressione regolare .NET (Regex) per la corrispondenza nel percorso dell'URL in ingresso. Il secondo parametro è la stringa di sostituzione. Il terzo parametro, se presente, specifica il codice di stato. Se il codice di stato non viene specificato, per impostazione predefinita il codice di stato è 302 - Trovato, che indica che la risorsa viene spostata o sostituita temporaneamente.

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

In un browser con gli strumenti di sviluppo abilitati, creare una richiesta all'app di esempio con il percorso /redirect-rule/1234/5678. L'espressione regolare corrisponde al percorso della richiesta in redirect-rule/(.*)e il percorso viene sostituito con /redirected/1234/5678. L'URL di reindirizzamento viene restituito al client con il codice di stato 302 - Trovato. Il browser invia una nuova richiesta all'URL di reindirizzamento, che viene visualizzata nella barra degli indirizzi del browser. Poiché nessuna regola nell'app di esempio corrisponde all'URL di reindirizzamento:

  • La seconda richiesta riceve una risposta 200 - OK dall'app.
  • Il corpo della risposta visualizza l'URL di reindirizzamento.

Quando un URL viene reindirizzato, viene eseguito un round trip al server.

Avviso

Prestare attenzione quando si definiscono regole di reindirizzamento. Le regole di reindirizzamento vengono valutate in ogni richiesta all'app, anche dopo un reindirizzamento. È facile creare inavvertitamente un ciclo di reindirizzamento infinito.

La parte dell'espressione racchiusa tra parentesi è denominata gruppo Capture. Il punto (.) dell'espressione significa corrispondenza con qualsiasi carattere. L'asterisco (*) indica corrispondenza con il carattere precedente per zero o più volte. Di conseguenza gli ultimi due i segmenti di percorso dell'URL 1234/5678 vengono acquisiti tramite il gruppo Capture (.*). Qualsiasi valore fornito nell'URL della richiesta dopo redirect-rule/ l'acquisizione da questo singolo gruppo di acquisizione.

Nella stringa di sostituzione i gruppi acquisiti vengono inseriti nella stringa con il simbolo di dollaro ($) seguito dal numero di sequenza dell'acquisizione. Il primo valore del gruppo di acquisizione viene ottenuto con $1, il secondo con $2e continuano in sequenza per i gruppi di acquisizione nell'espressione regolare. Esiste un solo gruppo acquisito nell'espressione regolare della regola di reindirizzamento in redirect-rule/(.*), quindi nella stringa di sostituzione è presente un solo gruppo inserito, ovvero $1. Quando viene applicata la regola, l'URL diventa /redirected/1234/5678.

Provare /redirect-rule/1234/5678 con gli strumenti del browser nella scheda di rete.

Reindirizzamento URL a un endpoint protetto

Usare AddRedirectToHttps per reindirizzare le richieste HTTP allo stesso host e allo stesso percorso tramite il protocollo HTTPS. Se il codice di stato non viene specificato, il middleware usa come valore predefinito 302 - Trovato. Se non viene specificata la porta:

  • Il middleware usa come valore predefinito null.
  • Lo schema viene modificato in https (protocollo HTTPS) e il client accede alla risorsa attraverso la porta 443.

L'esempio seguente illustra come impostare il codice 301 - Moved Permanently di stato su e modificare la porta sulla porta HTTPS usata da Kestrel in localhost. Nell'ambiente di produzione la porta HTTPS è impostata su 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();

Usare AddRedirectToHttpsPermanent per reindirizzare le richieste non protette allo stesso host e allo stesso percorso con il protocollo protetto HTTPS attraverso la porta 443. Il middleware imposta il codice di stato su 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();

Nota

Per il reindirizzamento a un endpoint protetto quando non sono richieste regole di reindirizzamento aggiuntive, è consigliabile usare il middleware di reindirizzamento HTTPS. Per altre informazioni, vedere Applicare HTTPS.

L'app di esempio illustra come usare AddRedirectToHttps o AddRedirectToHttpsPermanent. Effettuare una richiesta HTTP non sicura all'app all'indirizzo http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz. Durante il test del reindirizzamento DA HTTP a HTTPS con localhost:

  • Usare l'URL HTTP, che ha una porta diversa rispetto all'URL HTTPS. L'URL HTTP si trova nel Properties/launchSettings.json file .
  • La rimozione di s da https://localhost/{port} ha esito negativo perché localhost non risponde su HTTP alla porta HTTPS.

L'immagine seguente mostra l'immagine degli strumenti del browser F12 di una richiesta all'uso http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz del codice precedente:

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

Riscrittura URL

Usare AddRewrite per creare una regola di riscrittura URL. Il primo parametro contiene l'espressione regolare per la corrispondenza nel percorso URL in ingresso. Il secondo parametro è la stringa di sostituzione. Il terzo parametro, skipRemainingRules: {true|false}, indica al middleware se ignorare le regole di riscrittura aggiuntive quando viene applicata la regola corrente.

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

Provare la richiesta a https://redirect6.azurewebsites.net/rewrite-rule/1234/5678

Il punto di inserimento (^) all'inizio dell'espressione indica che la corrispondenza inizia all'inizio del percorso URL.

Nell'esempio precedente con la regola di reindirizzamento , redirect-rule/(.*)non è presente alcun cursore (^) all'inizio dell'espressione regolare. È quindi possibile ottenere una corrispondenza anteponendo qualsiasi carattere a redirect-rule/.

Percorso Corrispondenza
/redirect-rule/1234/5678
/my-cool-redirect-rule/1234/5678
/anotherredirect-rule/1234/5678

La regola di riscrittura, ^rewrite-rule/(\d+)/(\d+), rileva la corrispondenza dei percorsi solo se iniziano con rewrite-rule/. Nella tabella seguente, si noti la differenza nella corrispondenza.

Percorso Corrispondenza
/rewrite-rule/1234/5678
/my-cool-rewrite-rule/1234/5678 No
/anotherrewrite-rule/1234/5678 No

Dopo la parte ^rewrite-rule/ dell'espressione sono presenti due gruppi Capture, (\d+)/(\d+). \d indica corrispondenza con una cifra (numero). Il segno più (+) indica corrispondenza con uno o più dei caratteri precedenti. Di conseguenza l'URL deve contenere un numero seguito da una barra seguita a sua volta da un altro numero. Questi gruppi Capture vengono inseriti nell'URL riscritto come $1 e $2. La stringa di sostituzione della regola di riscrittura inserisce i gruppi acquisiti nella stringa di query. Il percorso /rewrite-rule/1234/5678 richiesto viene riscritto per restituire la risorsa in /rewritten?var1=1234&var2=5678. Se nella richiesta originale è presente una stringa di query, la stringa viene mantenuta quando l'URL viene riscritto.

Non è previsto alcun round trip al server per restituire la risorsa. Se la risorsa esiste, viene recuperata e restituita al client con il codice di stato 200 - OK. Poiché il client non è reindirizzato, l'URL nella barra degli indirizzi del browser non cambia. I client non sono in grado di rilevare che si è verificata un'operazione di riscrittura URL nel server.

Suggerimenti sulle prestazioni per la riscrittura e il reindirizzamento degli URL

Per la risposta più rapida:

  • Ordinare le regole di riscrittura dalla regola che origina più corrispondenze a quella che origina meno corrispondenze.
  • Se possibile, usare sempre skipRemainingRules: true, perché la corrispondenza tra le regole è onerosa dal punto di vista del calcolo e aumenta il tempo di risposta dell'app. Quando viene rilevata una corrispondenza e non sono necessarie altre operazioni di elaborazione delle regole, ignorare l'elaborazione delle regole rimanenti.

Avviso

Un utente malintenzionato può fornire costi elevati per elaborare l'input per RegularExpressions causare un attacco Denial of Service. ASP.NET API del framework core che usano RegularExpressions passano un timeout. Ad esempio, le classi RedirectRule e RewriteRule passano entrambi un secondo timeout.

Modulo Apache mod_rewrite

Applicare le regole del modulo Apache mod_rewrite con AddApacheModRewrite. Assicurarsi che il file delle regole venga distribuito con l'app. Per altre informazioni ed esempi di regole mod_rewrite, vedere Modulo Apache mod_rewrite.

Per leggere le regole del file di regole ApacheModRewrite.txt si usa StreamReader:

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

L'app di esempio reindirizza le richieste da /apache-mod-rules-redirect/(.\*) a /redirected?id=$1. Il codice di stato della risposta è 302 - Trovato.

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

Provare la richiesta a https://redirect6.azurewebsites.net/apache-mod-rules-redirect/1234

Il middleware Apache supporta le variabili del server Apache mod_rewrite seguenti:

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

Regole di IIS URL Rewrite Module

Per usare lo stesso set di regole applicabile a IIS URL Rewrite Module, usare AddIISUrlRewrite. Assicurarsi che il file delle regole venga distribuito con l'app. Non indirizzare il middleware all'uso del file web.config dell'app quando è in esecuzione in Windows Server IIS. Con IIS queste regole devono essere archiviate al di fuori del file web.config dell'app, per evitare conflitti con il modulo IIS Rewrite. Per altre informazioni ed esempi di regole di IIS URL Rewrite Module, vedere Using URL Rewrite Module 2.0 (Uso di URL Rewrite Module 2.0) e URL Rewrite Module Configuration Reference (Guida di riferimento per la configurazione di URL Rewrite Module).

Un StreamReader oggetto viene usato per leggere le regole dal IISUrlRewrite.xml file delle regole:

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

L'app di esempio riscrive le richieste da /iis-rules-rewrite/(.*) a /rewritten?id=$1. La risposta viene inviata al client con il codice di stato 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>

Provare la richiesta a https://redirect6.azurewebsites.net/iis-rules-rewrite/xyz

App con un modulo di riscrittura IIS attivo con regole a livello di server configurate che influisce sull'app in modi indesiderati:

  • Valutare la possibilità di disabilitare il modulo di riscrittura IIS per l'app.
  • Per altre informazioni, vedere Disabling IIS modules (Disabilitazione di moduli IIS).

Funzionalità non supportate

Il middleware non supporta le funzionalità del modulo di riscrittura URL IIS seguenti:

  • Regole in uscita
  • Variabili server personalizzate
  • Caratteri jolly
  • LogRewrittenUrl

Variabili server supportate

Il middleware supporta le variabili del server del server IIS URL Rewrite Module seguenti:

  • 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

IFileProviderpuò essere ottenuto tramite .PhysicalFileProvider Questo approccio può offrire maggiore flessibilità per il percorso dei file delle regole di riscrittura. Assicurarsi che i file delle regole di riscrittura vengano distribuiti nel server nel percorso specificato.

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

Regola basata su metodo

Usare Add per implementare la logica della regola personalizzata in un metodo . Add espone l'oggetto RewriteContext, che rende disponibile per l'uso HttpContext nei metodi di reindirizzamento. La RewriteContext.Result proprietà determina la modalità di gestione dell'elaborazione della pipeline aggiuntiva. Impostare il valore su uno dei campi RuleResult descritti nella tabella seguente.

Riscrittura del risultato del contesto Azione
RuleResult.ContinueRules (predefinito) Continuare ad applicare le regole.
RuleResult.EndResponse Interrompere l'applicazione delle regole e inviare la risposta.
RuleResult.SkipRemainingRules Interrompere l'applicazione delle regole e inviare il contesto al middleware successivo.
using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

L'app di esempio illustra un metodo che reindirizza le richieste per i percorsi che terminano con .xml. Quando viene effettuata una richiesta per /file.xml:

  • La richiesta viene reindirizzata a /xmlfiles/file.xml
  • Il codice di stato è impostato su 301 - Moved Permanently. Quando il browser effettua una nuova richiesta per /xmlfiles/file.xml, il middleware dei file statici serve il file al client dalla cartella wwwroot/xmlfiles . Per un reindirizzamento, impostare in modo esplicito il codice di stato della risposta. In caso contrario, viene restituito il codice di stato 200 - OK e il reindirizzamento non viene eseguito nel client.

RewriteRules.cs:

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

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

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

Questo approccio consente anche di riscrivere le richieste. L'app di esempio illustra la riscrittura del percorso di una richiesta di file di testo per rendere disponibile il file di testo file. txt dalla cartella wwwroot. Il middleware dei file statici rende disponibile il file in base al percorso di richiesta aggiornato:

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

Regola basata su IRule

Usare Add per usare la logica della regola in una classe che implementa l'interfaccia IRule. IRule garantisce maggiore flessibilità rispetto all'approccio con una regola basata su un metodo. La classe di implementazione può includere un costruttore che consente il passaggio di parametri per il ApplyRule metodo .

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

I valori dei parametri nell'app di esempio per extension e newPath vengono verificati e devono soddisfare diverse condizioni. Deve extension contenere un valore e il valore deve essere .png, .jpgo .gif. Se newPath non è valido, viene generato un evento ArgumentException. Se viene inviata una richiesta per image.png, la richiesta viene reindirizzata a /png-images/image.png. Se viene inviata una richiesta per image.jpg, la richiesta viene reindirizzata a /jpg-images/image.jpg. Il codice di stato è impostato su 301 - Moved Permanentlye context.Result è impostato per arrestare le regole di elaborazione e inviare la risposta.

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

Provare:

  • Richiesta PNG: https://redirect6.azurewebsites.net/image.png
  • Richiesta JPG: https://redirect6.azurewebsites.net/image.jpg

Esempi di espressioni regolari

Goal Esempio di stringa espressione regolare
e corrispondenza
Esempio di stringa di sostituzione
Output di esempio
Riscrivere il percorso nella stringa di query ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Rimuovere la barra finale ^path2/(.*)/$
/path2/xyz/
$1
/path2/xyz
Applicare la barra finale ^path3/(.*[^/])$
/path3/xyz
$1/
/path3/xyz/
Evitare la riscrittura di richieste specifiche ^(.*)(?<!\.axd)$ O
^(?!.*\.axd$)(.*)$
Sì: /path4/resource.htm
No: /path4/resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Ridisporre i segmenti di URL path5/(.*)/(.*)/(.*)
path5/1/2/3
path5/$3/$2/$1
path5/3/2/1
Sostituire un segmento di URL ^path6/(.*)/segment2/(.*)
^path6/segment1/segment2/segment3
path6/$1/replaced/$2
/path6/segment1/replaced/segment3

I collegamenti nella tabella precedente usano il codice seguente distribuito in 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();

Nella maggior parte degli esempi di espressioni regolari precedenti, il valore letterale path viene usato per rendere univoche regole di riscrittura testabili per l'esempio distribuito. In genere l'espressione regolare non include path. Ad esempio, vedere la tabella di esempi di espressioni regolari.

Questo documento presenta la riscrittura URL con istruzioni per l'uso del middleware Riscrittura URL nelle applicazioni ASP.NET Core.

La riscrittura URL è l'azione di modificare gli URL di richiesta in base a una o più regole predefinite. Il processo di riscrittura URL crea un'astrazione tra i percorsi delle risorse e i relativi indirizzi, in modo che i percorsi e gli indirizzi non risultino strettamente collegati. La riscrittura URL risulta utile in diversi scenari per:

  • Spostare o sostituire in modo temporaneo o permanente risorse server mantenendo localizzatori stabili di queste risorse.
  • Suddividere l'elaborazione delle richieste tra app diverse o tra aree diverse di un'unica app.
  • Rimuovere, aggiungere o riorganizzare segmenti URL nelle richieste in ingresso.
  • Ottimizzare gli URL pubblici per l'ottimizzazione motore di ricerca (SEO, Search Engine Optimization).
  • Consentire l'uso di URL pubblici descrittivi in modo che i visitatori possano prevedere il contenuto restituito dalla richiesta di una risorsa.
  • Reindirizzare le richieste non protette a endpoint protetti.
  • Evitare l'hotlinking, ovvero l'uso da parte di un sito esterno di una risorsa statica ospitata presente in un altro sito tramite il collegamento di questa al proprio contenuto.

Nota

La riscrittura URL può ridurre le prestazioni di un'app. Ove possibile, limitare il numero e la complessità delle regole.

Visualizzare o scaricare il codice di esempio (procedura per il download)

Reindirizzamento URL e riscrittura URL

La differenza tra i termini reindirizzamento URL e riscrittura URL è minima, ma ha implicazioni importanti nell'offerta di risorse ai clienti. Il middleware Riscrittura URL di ASP.NET Core è in grado di svolgere entrambe le funzioni.

Un reindirizzamento URL implica un'operazione lato client, in cui viene richiesto al client di accedere a una risorsa a un indirizzo diverso da quello richiesto originariamente dal client. Questa operazione richiede un round trip al server. L'URL di reindirizzamento restituito al client viene visualizzato nella barra degli indirizzi del browser quando il client effettua una nuova richiesta per la risorsa.

In caso di reindirizzamento di /resource a /different-resource, il server risponde che il client deve ottenere la risorsa presso /different-resource con un codice di stato che indica se il reindirizzamento è temporaneo o permanente.

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

Quando si reindirizzano le richieste a un URL diverso, indicare se il reindirizzamento è temporaneo o permanente specificando il codice di stato con la risposta:

  • Il 301 - Moved Permanently codice di stato viene usato in cui la risorsa ha un nuovo URL permanente e si vuole indicare al client che tutte le richieste future per la risorsa devono usare il nuovo URL. Quando riceve un codice di stato 301, il client può memorizzare la risposta nella cache e riusarla.

  • Il codice di stato 302 - Trovato viene usato quando il reindirizzamento è temporaneo o comunque soggetto a modifiche. Il codice di stato 302 indica che il client non dovrà archiviare e riusare l'URL di reindirizzamento in futuro.

Per altre informazioni sui codici di stato, vedere RFC 9110: Definizioni di codice di stato.

La riscrittura URL è un'operazione lato server che rende disponibile una risorsa da un indirizzo diverso da quello richiesto dal client. La riscrittura URL non richiede un round trip al server. L'URL riscritto non viene restituito al client e non viene visualizzato nella barra degli indirizzi del browser.

Se /resource viene riscritto in /different-resource, il server recupera internamente la risorsa in /different-resource.

Anche se il client fosse in grado di recuperare la risorsa nell'URL riscritto, non viene informato dell'esistenza della risorsa nell'URL riscritto quando effettua la richiesta e riceve la risposta.

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.

App di esempio per la riscrittura URL

È possibile esplorare le funzionalità del middleware Riscrittura URL con l'app di esempio. L'app applica regole di reindirizzamento e riscrittura e visualizza l'URL reindirizzato o riscritto per diversi scenari.

Quando usare il middleware di riscrittura URL

Usare il middleware Riscrittura URL quando non è possibile usare gli approcci seguenti:

Usare il middleware di riscrittura url quando l'app è ospitata nel server HTTP.sys.

I motivi principali per usare tecnologie di riscrittura URL basate su server in IIS, Apache e Nginx sono:

  • Il middleware non supporta tutte le funzionalità di questi moduli.

    Alcune funzionalità dei moduli server non funzionano con i progetti ASP.NET Core, ad esempio i vincoli IsFile e IsDirectory del modulo IIS Rewrite. In questi scenari è necessario usare il middleware.

  • Le prestazioni del middleware probabilmente non corrispondono a quelle dei moduli.

    Il benchmarking rappresenta l'unico modo per sapere con certezza quale approccio comporta la maggior riduzione delle prestazioni o se tale riduzione è trascurabile.

Pacchetto

Il middleware di riscrittura URL è fornito dal pacchetto Microsoft.AspNetCore.Rewrite, implicitamente incluso nelle app ASP.NET Core.

Estensioni e opzioni

È possibile definire regole di riscrittura e reindirizzamento URL creando un'istanza della classe RewriteOptions con metodi di estensione per le singole regole di riscrittura. Concatenare più regole nell'ordine in cui si vuole che vengano elaborate. Le opzioni RewriteOptions vengono passate al middleware Riscrittura URL quando questo viene aggiunto alla pipeline della richiesta con 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}"));
}

Reindirizzare non-www su www

Sono disponibili tre opzioni che consentono all'app di reindirizzare richieste non-www su www:

Reindirizzamento URL

Per reindirizzare le richieste, usare AddRedirect. Il primo parametro contiene regex per la corrispondenza nel percorso dell'URL in ingresso. Il secondo parametro è la stringa di sostituzione. Il terzo parametro, se presente, specifica il codice di stato. Se il codice di stato non è specificato, assume come valore predefinito 302 - Trovato, che indica che la risorsa è stata temporaneamente spostata o sostituita.

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

In un browser con gli strumenti di sviluppo abilitati, creare una richiesta all'app di esempio con il percorso /redirect-rule/1234/5678. L'espressione regolare definisce la corrispondenza con il percorso di richiesta in redirect-rule/(.*) e il percorso viene sostituito con /redirected/1234/5678. L'URL di reindirizzamento viene restituito al client con il codice di stato 302 - Trovato. Il browser invia una nuova richiesta all'URL di reindirizzamento, che viene visualizzata nella barra degli indirizzi del browser. Poiché nessuna regola nell'app di esempio corrisponde all'URL di reindirizzamento:

  • La seconda richiesta riceve una risposta 200 - OK dall'app.
  • Il corpo della risposta visualizza l'URL di reindirizzamento.

Quando un URL viene reindirizzato, viene eseguito un round trip al server.

Avviso

Prestare attenzione quando si definiscono regole di reindirizzamento. Le regole di reindirizzamento vengono valutate in ogni richiesta all'app, anche dopo un reindirizzamento. È facile creare inavvertitamente un ciclo di reindirizzamento infinito.

Richiesta originale: /redirect-rule/1234/5678

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

La parte dell'espressione racchiusa tra parentesi è denominata gruppo Capture. Il punto (.) dell'espressione significa corrispondenza con qualsiasi carattere. L'asterisco (*) indica corrispondenza con il carattere precedente per zero o più volte. Di conseguenza gli ultimi due i segmenti di percorso dell'URL 1234/5678 vengono acquisiti tramite il gruppo Capture (.*). Qualsiasi valore visualizzato nell'URL della richiesta dopo redirect-rule/ viene acquisito da questo gruppo Capture.

Nella stringa di sostituzione i gruppi acquisiti vengono inseriti nella stringa con il simbolo di dollaro ($) seguito dal numero di sequenza dell'acquisizione. Il primo valore del gruppo Capture viene ottenuto con $1, il secondo con $2 e la procedura continua in sequenza per i gruppi Capture presenti nell'espressione regolare. Nell'espressione regolare della regola di reindirizzamento dell'app di esempio è presente un solo gruppo acquisito, pertanto nella stringa di sostituzione è presente un solo gruppo inserito, ovvero $1. Quando viene applicata la regola, l'URL diventa /redirected/1234/5678.

Reindirizzamento URL a un endpoint protetto

Usare AddRedirectToHttps per reindirizzare le richieste HTTP allo stesso host e allo stesso percorso tramite il protocollo HTTPS. Se il codice di stato non viene specificato, il middleware usa come valore predefinito 302 - Trovato. Se non viene specificata la porta:

  • Il middleware usa come valore predefinito null.
  • Lo schema viene modificato in https (protocollo HTTPS) e il client accede alla risorsa attraverso la porta 443.

Nell'esempio seguente viene illustrato come impostare il codice di stato su 301 - Moved Permanently e modificare la porta su 5001.

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

    app.UseRewriter(options);
}

Usare AddRedirectToHttpsPermanent per reindirizzare le richieste non protette allo stesso host e allo stesso percorso con il protocollo protetto HTTPS attraverso la porta 443. Il middleware imposta il codice di stato su 301 - Moved Permanently.

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

    app.UseRewriter(options);
}

Nota

Per il reindirizzamento a un endpoint protetto quando non sono richieste regole di reindirizzamento aggiuntive, è consigliabile usare il middleware di reindirizzamento HTTPS. Per altre informazioni, vedere l'argomento Imporre HTTPS.

L'app di esempio indica come usare AddRedirectToHttps o AddRedirectToHttpsPermanent. Aggiungere il metodo di estensione a RewriteOptions. Eseguire una richiesta non sicura all'app su qualsiasi URL. Ignorare l'avviso di sicurezza del browser indicante che il certificato autofirmato non è attendibile oppure creare un'eccezione per rendere affidabile il certificato.

Richiesta originale con AddRedirectToHttps(301, 5001): http://localhost:5000/secure

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

Richiesta originale con AddRedirectToHttpsPermanent: http://localhost:5000/secure

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

Riscrittura URL

Usare AddRewrite per creare una regola di riscrittura URL. Il primo parametro contiene l'espressione regolare per la corrispondenza in base al percorso dell'URL in ingresso. Il secondo parametro è la stringa di sostituzione. Il terzo parametro, skipRemainingRules: {true|false}, indica al middleware se ignorare le regole di riscrittura aggiuntive quando viene applicata la regola corrente.

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

Richiesta originale: /rewrite-rule/1234/5678

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

L'accento circonflesso (^) all'inizio dell'espressione indica che la corrispondenza inizia all'inizio del percorso dell'URL.

Nell'esempio precedente della regola di reindirizzamento redirect-rule/(.*), non è presente l'accento circonflesso (^) all'inizio dell'espressione regolare. È quindi possibile ottenere una corrispondenza anteponendo qualsiasi carattere a redirect-rule/.

Percorso Corrispondenza
/redirect-rule/1234/5678
/my-cool-redirect-rule/1234/5678
/anotherredirect-rule/1234/5678

La regola di riscrittura, ^rewrite-rule/(\d+)/(\d+), rileva la corrispondenza dei percorsi solo se iniziano con rewrite-rule/. Nella tabella seguente, si noti la differenza nella corrispondenza.

Percorso Corrispondenza
/rewrite-rule/1234/5678
/my-cool-rewrite-rule/1234/5678 No
/anotherrewrite-rule/1234/5678 No

Dopo la parte ^rewrite-rule/ dell'espressione sono presenti due gruppi Capture, (\d+)/(\d+). \d indica corrispondenza con una cifra (numero). Il segno più (+) indica corrispondenza con uno o più dei caratteri precedenti. Di conseguenza l'URL deve contenere un numero seguito da una barra seguita a sua volta da un altro numero. Questi gruppi Capture vengono inseriti nell'URL riscritto come $1 e $2. La stringa di sostituzione della regola di riscrittura inserisce i gruppi acquisiti nella stringa di query. Il percorso richiesto /rewrite-rule/1234/5678 viene riscritto per ottenere la risorsa in /rewritten?var1=1234&var2=5678. Se nella richiesta originale è presente una stringa di query, la stringa viene mantenuta quando l'URL viene riscritto.

Non viene eseguito alcun round trip al server per ottenere la risorsa. Se la risorsa esiste, viene recuperata e restituita al client con il codice di stato 200 - OK. Poiché il client non è reindirizzato, l'URL nella barra degli indirizzi del browser non cambia. I client non sono in grado di rilevare che si è verificata un'operazione di riscrittura URL nel server.

Nota

Se possibile, usare sempre skipRemainingRules: true, perché la corrispondenza tra le regole è onerosa dal punto di vista del calcolo e aumenta il tempo di risposta dell'app. Per velocizzare il tempo di risposta dell'app:

  • Ordinare le regole di riscrittura dalla regola che origina più corrispondenze a quella che origina meno corrispondenze.
  • Quando viene rilevata una corrispondenza e non sono necessarie altre operazioni di elaborazione delle regole, ignorare l'elaborazione delle regole rimanenti.

Modulo Apache mod_rewrite

Applicare le regole del modulo Apache mod_rewrite con AddApacheModRewrite. Assicurarsi che il file delle regole venga distribuito con l'app. Per altre informazioni ed esempi di regole mod_rewrite, vedere Modulo Apache mod_rewrite.

Per leggere le regole del file di regole ApacheModRewrite.txt si usa StreamReader:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

L'app di esempio reindirizza le richieste da /apache-mod-rules-redirect/(.\*) a /redirected?id=$1. Il codice di stato della risposta è 302 - Trovato.

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

Richiesta originale: /apache-mod-rules-redirect/1234

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

Il middleware supporta le seguenti variabili server del modulo Apache mod_rewrite:

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

Regole di IIS URL Rewrite Module

Per usare lo stesso set di regole applicabile a IIS URL Rewrite Module, usare AddIISUrlRewrite. Assicurarsi che il file delle regole venga distribuito con l'app. Non indirizzare il middleware all'uso del file web.config dell'app quando è in esecuzione in Windows Server IIS. Con IIS queste regole devono essere archiviate al di fuori del file web.config dell'app, per evitare conflitti con il modulo IIS Rewrite. Per altre informazioni ed esempi di regole di IIS URL Rewrite Module, vedere Using URL Rewrite Module 2.0 (Uso di URL Rewrite Module 2.0) e URL Rewrite Module Configuration Reference (Guida di riferimento per la configurazione di URL Rewrite Module).

Un StreamReader oggetto viene usato per leggere le regole dal IISUrlRewrite.xml file delle regole:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

L'app di esempio riscrive le richieste da /iis-rules-rewrite/(.*) a /rewritten?id=$1. La risposta viene inviata al client con il codice di stato 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>

Richiesta originale: /iis-rules-rewrite/1234

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

Se è presente un modulo IIS Rewrite attivo con regole di livello server configurate che possono avere effetti indesiderati nell'app, è possibile disabilitare il modulo IIS Rewrite per un'app. Per altre informazioni, vedere Disabling IIS modules (Disabilitazione di moduli IIS).

Funzionalità non supportate

Il middleware non supporta le funzionalità del modulo di riscrittura URL IIS seguenti:

  • Regole in uscita
  • Variabili server personalizzate
  • Caratteri jolly
  • LogRewrittenUrl

Variabili server supportate

Il middleware supporta le seguenti variabili server di IIS URL Rewrite Module:

  • 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

Nota

È anche possibile ottenere un IFileProvider tramite un PhysicalFileProvider. Questo approccio può garantire maggior flessibilità per la posizione dei file delle regole di riscrittura. Assicurarsi che i file di regole di riscrittura vengano distribuiti nel server in corrispondenza del percorso specificato.

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

Regola basata su metodo

Usare Add per implementare logica della regola personalizzata in un metodo. Add espone RewriteContext, che rende disponibile HttpContext per l'uso nel metodo. RewriteContext.Result determina la modalità di gestione dell'elaborazione pipeline aggiuntiva. Impostare il valore su uno dei campi RuleResult descritti nella tabella seguente.

Riscrittura del risultato del contesto Azione
RuleResult.ContinueRules (predefinito) Continuare ad applicare le regole.
RuleResult.EndResponse Interrompere l'applicazione delle regole e inviare la risposta.
RuleResult.SkipRemainingRules Interrompere l'applicazione delle regole e inviare il contesto al middleware successivo.
public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

L'app di esempio illustra un metodo che reindirizza le richieste per i percorsi che terminano con .xml. Se viene inviata una richiesta per /file.xml, la richiesta viene reindirizzata a /xmlfiles/file.xml. Il codice di stato è impostato su 301 - Moved Permanently. Quando il browser effettua una nuova richiesta per /xmlfiles/file.xml, il middleware dei file statici serve il file al client dalla cartella wwwroot/xmlfiles . Per un reindirizzamento, impostare in modo esplicito il codice di stato della risposta. In caso contrario, viene restituito il codice di stato 200 - OK e il reindirizzamento non viene eseguito nel client.

RewriteRules.cs:

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

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

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

Questo approccio consente anche di riscrivere le richieste. L'app di esempio illustra la riscrittura del percorso di una richiesta di file di testo per rendere disponibile il file di testo file. txt dalla cartella wwwroot. Il middleware dei file statici rende disponibile il file in base al percorso di richiesta aggiornato:

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

Regola basata su IRule

Usare Add per usare la logica della regola in una classe che implementa l'interfaccia IRule. IRule garantisce maggiore flessibilità rispetto all'approccio con una regola basata su un metodo. La classe di implementazione può includere un costruttore, che consente di passare parametri per il metodo ApplyRule.

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

I valori dei parametri nell'app di esempio per extension e newPath vengono verificati e devono soddisfare diverse condizioni. extension Deve contenere un valore e il valore deve essere .png, .jpgo .gif. Se newPath non è valido, viene generato un evento ArgumentException. Se viene inviata una richiesta per image.png, la richiesta viene reindirizzata a /png-images/image.png. Se viene inviata una richiesta per image.jpg, la richiesta viene reindirizzata a /jpg-images/image.jpg. Il codice di stato è impostato su 301 - Moved Permanentlye context.Result è impostato per arrestare le regole di elaborazione e inviare la risposta.

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

Richiesta originale: /image.png

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

Richiesta originale: /image.jpg

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

Esempi di espressioni regolari

Goal Esempio di stringa espressione regolare
e corrispondenza
Esempio di stringa di sostituzione
Output di esempio
Riscrivere il percorso nella stringa di query ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Rimuovere la barra finale (.*)/$
/path/
$1
/path
Applicare la barra finale (.*[^/])$
/path
$1/
/path/
Evitare la riscrittura di richieste specifiche ^(.*)(?<!\.axd)$ oppure ^(?!.*\.axd$)(.*)$
Sì: /resource.htm
No: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Ridisporre i segmenti di URL path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Sostituire un segmento di URL ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

Questo documento presenta la riscrittura URL con istruzioni per l'uso del middleware Riscrittura URL nelle applicazioni ASP.NET Core.

La riscrittura URL è l'azione di modificare gli URL di richiesta in base a una o più regole predefinite. Il processo di riscrittura URL crea un'astrazione tra i percorsi delle risorse e i relativi indirizzi, in modo che i percorsi e gli indirizzi non risultino strettamente collegati. La riscrittura URL risulta utile in diversi scenari per:

  • Spostare o sostituire in modo temporaneo o permanente risorse server mantenendo localizzatori stabili di queste risorse.
  • Suddividere l'elaborazione delle richieste tra app diverse o tra aree diverse di un'unica app.
  • Rimuovere, aggiungere o riorganizzare segmenti URL nelle richieste in ingresso.
  • Ottimizzare gli URL pubblici per l'ottimizzazione motore di ricerca (SEO, Search Engine Optimization).
  • Consentire l'uso di URL pubblici descrittivi in modo che i visitatori possano prevedere il contenuto restituito dalla richiesta di una risorsa.
  • Reindirizzare le richieste non protette a endpoint protetti.
  • Evitare l'hotlinking, ovvero l'uso da parte di un sito esterno di una risorsa statica ospitata presente in un altro sito tramite il collegamento di questa al proprio contenuto.

Nota

La riscrittura URL può ridurre le prestazioni di un'app. Ove possibile, limitare il numero e la complessità delle regole.

Visualizzare o scaricare il codice di esempio (procedura per il download)

Reindirizzamento URL e riscrittura URL

La differenza tra i termini reindirizzamento URL e riscrittura URL è minima, ma ha implicazioni importanti nell'offerta di risorse ai clienti. Il middleware Riscrittura URL di ASP.NET Core è in grado di svolgere entrambe le funzioni.

Un reindirizzamento URL implica un'operazione lato client, in cui viene richiesto al client di accedere a una risorsa a un indirizzo diverso da quello richiesto originariamente dal client. Questa operazione richiede un round trip al server. L'URL di reindirizzamento restituito al client viene visualizzato nella barra degli indirizzi del browser quando il client effettua una nuova richiesta per la risorsa.

In caso di reindirizzamento di /resource a /different-resource, il server risponde che il client deve ottenere la risorsa presso /different-resource con un codice di stato che indica se il reindirizzamento è temporaneo o permanente.

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

Quando si reindirizzano le richieste a un URL diverso, indicare se il reindirizzamento è temporaneo o permanente specificando il codice di stato con la risposta:

  • Il 301 - Moved Permanently codice di stato viene usato in cui la risorsa ha un nuovo URL permanente e si vuole indicare al client che tutte le richieste future per la risorsa devono usare il nuovo URL. Quando riceve un codice di stato 301, il client può memorizzare la risposta nella cache e riusarla.

  • Il codice di stato 302 - Trovato viene usato quando il reindirizzamento è temporaneo o comunque soggetto a modifiche. Il codice di stato 302 indica che il client non dovrà archiviare e riusare l'URL di reindirizzamento in futuro.

Per altre informazioni sui codici di stato, vedere RFC 9110: Definizioni di codice di stato.

La riscrittura URL è un'operazione lato server che rende disponibile una risorsa da un indirizzo diverso da quello richiesto dal client. La riscrittura URL non richiede un round trip al server. L'URL riscritto non viene restituito al client e non viene visualizzato nella barra degli indirizzi del browser.

Se /resource viene riscritto in /different-resource, il server recupera internamente la risorsa in /different-resource.

Anche se il client fosse in grado di recuperare la risorsa nell'URL riscritto, non viene informato dell'esistenza della risorsa nell'URL riscritto quando effettua la richiesta e riceve la risposta.

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.

App di esempio per la riscrittura URL

È possibile esplorare le funzionalità del middleware Riscrittura URL con l'app di esempio. L'app applica regole di reindirizzamento e riscrittura e visualizza l'URL reindirizzato o riscritto per diversi scenari.

Quando usare il middleware Riscrittura URL

Usare il middleware Riscrittura URL quando non è possibile usare gli approcci seguenti:

Usare il middleware anche se l'app è ospitata in un server HTTP.sys (in precedenza denominato WebListener).

I motivi principali per usare tecnologie di riscrittura URL basate su server in IIS, Apache e Nginx sono:

  • Il middleware non supporta tutte le funzionalità di questi moduli.

    Alcune funzionalità dei moduli server non funzionano con i progetti ASP.NET Core, ad esempio i vincoli IsFile e IsDirectory del modulo IIS Rewrite. In questi scenari è necessario usare il middleware.

  • Le prestazioni del middleware probabilmente non corrispondono a quelle dei moduli.

    Il benchmarking rappresenta l'unico modo per sapere con certezza quale approccio comporta la maggior riduzione delle prestazioni o se tale riduzione è trascurabile.

Pacchetto

Per includere il middleware nel progetto, aggiungere un riferimento al pacchetto al metapacchetto Microsoft.AspNetCore.App nel file di progetto, che contiene il pacchetto Microsoft.AspNetCore.Rewrite.

Se non si usa il metapacchetto Microsoft.AspNetCore.App, aggiungere un riferimento al progetto al pacchetto Microsoft.AspNetCore.Rewrite.

Estensioni e opzioni

È possibile definire regole di riscrittura e reindirizzamento URL creando un'istanza della classe RewriteOptions con metodi di estensione per le singole regole di riscrittura. Concatenare più regole nell'ordine in cui si vuole che vengano elaborate. Le opzioni RewriteOptions vengono passate al middleware Riscrittura URL quando questo viene aggiunto alla pipeline della richiesta con 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}"));
}

Reindirizzare non-www su www

Sono disponibili tre opzioni che consentono all'app di reindirizzare richieste non-www su www:

Reindirizzamento URL

Per reindirizzare le richieste, usare AddRedirect. Il primo parametro contiene l'espressione regolare per la corrispondenza in base al percorso dell'URL in ingresso. Il secondo parametro è la stringa di sostituzione. Il terzo parametro, se presente, specifica il codice di stato. Se il codice di stato non è specificato, assume come valore predefinito 302 - Trovato, che indica che la risorsa è stata temporaneamente spostata o sostituita.

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

In un browser con gli strumenti di sviluppo abilitati, creare una richiesta all'app di esempio con il percorso /redirect-rule/1234/5678. L'espressione regolare definisce la corrispondenza con il percorso di richiesta in redirect-rule/(.*) e il percorso viene sostituito con /redirected/1234/5678. L'URL di reindirizzamento viene restituito al client con il codice di stato 302 - Trovato. Il browser invia una nuova richiesta all'URL di reindirizzamento, che viene visualizzata nella barra degli indirizzi del browser. Poiché nessuna regola nell'app di esempio corrisponde all'URL di reindirizzamento:

  • La seconda richiesta riceve una risposta 200 - OK dall'app.
  • Il corpo della risposta visualizza l'URL di reindirizzamento.

Quando un URL viene reindirizzato, viene eseguito un round trip al server.

Avviso

Prestare attenzione quando si definiscono regole di reindirizzamento. Le regole di reindirizzamento vengono valutate in ogni richiesta all'app, anche dopo un reindirizzamento. È facile creare inavvertitamente un ciclo di reindirizzamento infinito.

Richiesta originale: /redirect-rule/1234/5678

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

La parte dell'espressione racchiusa tra parentesi è denominata gruppo Capture. Il punto (.) dell'espressione significa corrispondenza con qualsiasi carattere. L'asterisco (*) indica corrispondenza con il carattere precedente per zero o più volte. Di conseguenza gli ultimi due i segmenti di percorso dell'URL 1234/5678 vengono acquisiti tramite il gruppo Capture (.*). Qualsiasi valore visualizzato nell'URL della richiesta dopo redirect-rule/ viene acquisito da questo gruppo Capture.

Nella stringa di sostituzione i gruppi acquisiti vengono inseriti nella stringa con il simbolo di dollaro ($) seguito dal numero di sequenza dell'acquisizione. Il primo valore del gruppo Capture viene ottenuto con $1, il secondo con $2 e la procedura continua in sequenza per i gruppi Capture presenti nell'espressione regolare. Nell'espressione regolare della regola di reindirizzamento dell'app di esempio è presente un solo gruppo acquisito, pertanto nella stringa di sostituzione è presente un solo gruppo inserito, ovvero $1. Quando viene applicata la regola, l'URL diventa /redirected/1234/5678.

Reindirizzamento URL a un endpoint protetto

Usare AddRedirectToHttps per reindirizzare le richieste HTTP allo stesso host e allo stesso percorso tramite il protocollo HTTPS. Se il codice di stato non viene specificato, il middleware usa come valore predefinito 302 - Trovato. Se non viene specificata la porta:

  • Il middleware usa come valore predefinito null.
  • Lo schema viene modificato in https (protocollo HTTPS) e il client accede alla risorsa attraverso la porta 443.

Nell'esempio seguente viene illustrato come impostare il codice di stato su 301 - Moved Permanently e modificare la porta su 5001.

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

    app.UseRewriter(options);
}

Usare AddRedirectToHttpsPermanent per reindirizzare le richieste non protette allo stesso host e allo stesso percorso con il protocollo protetto HTTPS attraverso la porta 443. Il middleware imposta il codice di stato su 301 - Moved Permanently.

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

    app.UseRewriter(options);
}

Nota

Per il reindirizzamento a un endpoint protetto quando non sono richieste regole di reindirizzamento aggiuntive, è consigliabile usare il middleware di reindirizzamento HTTPS. Per altre informazioni, vedere l'argomento Imporre HTTPS.

L'app di esempio indica come usare AddRedirectToHttps o AddRedirectToHttpsPermanent. Aggiungere il metodo di estensione a RewriteOptions. Eseguire una richiesta non sicura all'app su qualsiasi URL. Ignorare l'avviso di sicurezza del browser indicante che il certificato autofirmato non è attendibile oppure creare un'eccezione per rendere affidabile il certificato.

Richiesta originale con AddRedirectToHttps(301, 5001): http://localhost:5000/secure

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

Richiesta originale con AddRedirectToHttpsPermanent: http://localhost:5000/secure

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

Riscrittura URL

Usare AddRewrite per creare una regola di riscrittura URL. Il primo parametro contiene l'espressione regolare per la corrispondenza in base al percorso dell'URL in ingresso. Il secondo parametro è la stringa di sostituzione. Il terzo parametro, skipRemainingRules: {true|false}, indica al middleware se ignorare le regole di riscrittura aggiuntive quando viene applicata la regola corrente.

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

Richiesta originale: /rewrite-rule/1234/5678

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

L'accento circonflesso (^) all'inizio dell'espressione indica che la corrispondenza inizia all'inizio del percorso dell'URL.

Nell'esempio precedente della regola di reindirizzamento redirect-rule/(.*), non è presente l'accento circonflesso (^) all'inizio dell'espressione regolare. È quindi possibile ottenere una corrispondenza anteponendo qualsiasi carattere a redirect-rule/.

Percorso Corrispondenza
/redirect-rule/1234/5678
/my-cool-redirect-rule/1234/5678
/anotherredirect-rule/1234/5678

La regola di riscrittura, ^rewrite-rule/(\d+)/(\d+), rileva la corrispondenza dei percorsi solo se iniziano con rewrite-rule/. Nella tabella seguente, si noti la differenza nella corrispondenza.

Percorso Corrispondenza
/rewrite-rule/1234/5678
/my-cool-rewrite-rule/1234/5678 No
/anotherrewrite-rule/1234/5678 No

Dopo la parte ^rewrite-rule/ dell'espressione sono presenti due gruppi Capture, (\d+)/(\d+). \d indica corrispondenza con una cifra (numero). Il segno più (+) indica corrispondenza con uno o più dei caratteri precedenti. Di conseguenza l'URL deve contenere un numero seguito da una barra seguita a sua volta da un altro numero. Questi gruppi Capture vengono inseriti nell'URL riscritto come $1 e $2. La stringa di sostituzione della regola di riscrittura inserisce i gruppi acquisiti nella stringa di query. Il percorso richiesto /rewrite-rule/1234/5678 viene riscritto per ottenere la risorsa in /rewritten?var1=1234&var2=5678. Se nella richiesta originale è presente una stringa di query, la stringa viene mantenuta quando l'URL viene riscritto.

Non viene eseguito alcun round trip al server per ottenere la risorsa. Se la risorsa esiste, viene recuperata e restituita al client con il codice di stato 200 - OK. Poiché il client non è reindirizzato, l'URL nella barra degli indirizzi del browser non cambia. I client non sono in grado di rilevare che si è verificata un'operazione di riscrittura URL nel server.

Nota

Se possibile, usare sempre skipRemainingRules: true, perché la corrispondenza tra le regole è onerosa dal punto di vista del calcolo e aumenta il tempo di risposta dell'app. Per velocizzare il tempo di risposta dell'app:

  • Ordinare le regole di riscrittura dalla regola che origina più corrispondenze a quella che origina meno corrispondenze.
  • Quando viene rilevata una corrispondenza e non sono necessarie altre operazioni di elaborazione delle regole, ignorare l'elaborazione delle regole rimanenti.

Modulo Apache mod_rewrite

Applicare le regole del modulo Apache mod_rewrite con AddApacheModRewrite. Assicurarsi che il file delle regole venga distribuito con l'app. Per altre informazioni ed esempi di regole mod_rewrite, vedere Modulo Apache mod_rewrite.

Per leggere le regole del file di regole ApacheModRewrite.txt si usa StreamReader:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

L'app di esempio reindirizza le richieste da /apache-mod-rules-redirect/(.\*) a /redirected?id=$1. Il codice di stato della risposta è 302 - Trovato.

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

Richiesta originale: /apache-mod-rules-redirect/1234

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

Il middleware supporta le seguenti variabili server del modulo Apache mod_rewrite:

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

Regole di IIS URL Rewrite Module

Per usare lo stesso set di regole applicabile a IIS URL Rewrite Module, usare AddIISUrlRewrite. Assicurarsi che il file delle regole venga distribuito con l'app. Non indirizzare il middleware all'uso del file web.config dell'app quando è in esecuzione in Windows Server IIS. Con IIS queste regole devono essere archiviate al di fuori del file web.config dell'app, per evitare conflitti con il modulo IIS Rewrite. Per altre informazioni ed esempi di regole di IIS URL Rewrite Module, vedere Using URL Rewrite Module 2.0 (Uso di URL Rewrite Module 2.0) e URL Rewrite Module Configuration Reference (Guida di riferimento per la configurazione di URL Rewrite Module).

Un StreamReader oggetto viene usato per leggere le regole dal IISUrlRewrite.xml file delle regole:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

L'app di esempio riscrive le richieste da /iis-rules-rewrite/(.*) a /rewritten?id=$1. La risposta viene inviata al client con il codice di stato 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>

Richiesta originale: /iis-rules-rewrite/1234

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

Se è presente un modulo IIS Rewrite attivo con regole di livello server configurate che possono avere effetti indesiderati nell'app, è possibile disabilitare il modulo IIS Rewrite per un'app. Per altre informazioni, vedere Disabling IIS modules (Disabilitazione di moduli IIS).

Funzionalità non supportate

Il middleware rilasciato con ASP.NET Core 2.x non supporta le seguenti funzionalità di IIS URL Rewrite Module:

  • Regole in uscita
  • Variabili server personalizzate
  • Caratteri jolly
  • LogRewrittenUrl

Variabili server supportate

Il middleware supporta le seguenti variabili server di IIS URL Rewrite Module:

  • 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

Nota

È anche possibile ottenere un IFileProvider tramite un PhysicalFileProvider. Questo approccio può garantire maggior flessibilità per la posizione dei file delle regole di riscrittura. Assicurarsi che i file di regole di riscrittura vengano distribuiti nel server in corrispondenza del percorso specificato.

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

Regola basata su metodo

Usare Add per implementare logica della regola personalizzata in un metodo. Add espone RewriteContext, che rende disponibile HttpContext per l'uso nel metodo. RewriteContext.Result determina la modalità di gestione dell'elaborazione pipeline aggiuntiva. Impostare il valore su uno dei campi RuleResult descritti nella tabella seguente.

Riscrittura del risultato del contesto Azione
RuleResult.ContinueRules (predefinito) Continuare ad applicare le regole.
RuleResult.EndResponse Interrompere l'applicazione delle regole e inviare la risposta.
RuleResult.SkipRemainingRules Interrompere l'applicazione delle regole e inviare il contesto al middleware successivo.
public void Configure(IApplicationBuilder app)
{
    using (StreamReader apacheModRewriteStreamReader = 
        File.OpenText("ApacheModRewrite.txt"))
    using (StreamReader iisUrlRewriteStreamReader = 
        File.OpenText("IISUrlRewrite.xml")) 
    {
        var options = new RewriteOptions()
            .AddRedirect("redirect-rule/(.*)", "redirected/$1")
            .AddRewrite(@"^rewrite-rule/(\d+)/(\d+)", "rewritten?var1=$1&var2=$2", 
                skipRemainingRules: true)
            .AddApacheModRewrite(apacheModRewriteStreamReader)
            .AddIISUrlRewrite(iisUrlRewriteStreamReader)
            .Add(MethodRules.RedirectXmlFileRequests)
            .Add(MethodRules.RewriteTextFileRequests)
            .Add(new RedirectImageRequests(".png", "/png-images"))
            .Add(new RedirectImageRequests(".jpg", "/jpg-images"));

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

L'app di esempio illustra un metodo che reindirizza le richieste per i percorsi che terminano con .xml. Se viene inviata una richiesta per /file.xml, la richiesta viene reindirizzata a /xmlfiles/file.xml. Il codice di stato è impostato su 301 - Moved Permanently. Quando il browser effettua una nuova richiesta per /xmlfiles/file.xml, il middleware dei file statici serve il file al client dalla cartella wwwroot/xmlfiles . Per un reindirizzamento, impostare in modo esplicito il codice di stato della risposta. In caso contrario, viene restituito il codice di stato 200 - OK e il reindirizzamento non viene eseguito nel client.

RewriteRules.cs:

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

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

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

Questo approccio consente anche di riscrivere le richieste. L'app di esempio illustra la riscrittura del percorso di una richiesta di file di testo per rendere disponibile il file di testo file. txt dalla cartella wwwroot. Il middleware dei file statici rende disponibile il file in base al percorso di richiesta aggiornato:

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

Regola basata su IRule

Usare Add per usare la logica della regola in una classe che implementa l'interfaccia IRule. IRule garantisce maggiore flessibilità rispetto all'approccio con una regola basata su un metodo. La classe di implementazione può includere un costruttore, che consente di passare parametri per il metodo ApplyRule.

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

I valori dei parametri nell'app di esempio per extension e newPath vengono verificati e devono soddisfare diverse condizioni. extension Deve contenere un valore e il valore deve essere .png, .jpgo .gif. Se newPath non è valido, viene generato un evento ArgumentException. Se viene inviata una richiesta per image.png, la richiesta viene reindirizzata a /png-images/image.png. Se viene inviata una richiesta per image.jpg, la richiesta viene reindirizzata a /jpg-images/image.jpg. Il codice di stato è impostato su 301 - Moved Permanentlye context.Result è impostato per arrestare le regole di elaborazione e inviare la risposta.

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

Richiesta originale: /image.png

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

Richiesta originale: /image.jpg

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

Esempi di espressioni regolari

Goal Esempio di stringa espressione regolare
e corrispondenza
Esempio di stringa di sostituzione
Output di esempio
Riscrivere il percorso nella stringa di query ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Rimuovere la barra finale (.*)/$
/path/
$1
/path
Applicare la barra finale (.*[^/])$
/path
$1/
/path/
Evitare la riscrittura di richieste specifiche ^(.*)(?<!\.axd)$ oppure ^(?!.*\.axd$)(.*)$
Sì: /resource.htm
No: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Ridisporre i segmenti di URL path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Sostituire un segmento di URL ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

Risorse aggiuntive