Middleware Riscrittura URL in ASP.NET Core
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 8 di questo articolo.
Importante
Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Per la versione corrente, vedere la versione .NET 8 di questo articolo.
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.
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.
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:
- URL Rewrite Module for IIS in Windows Server
- Modulo Apache mod_rewrite in Apache Server
- Riscrittura URL in Nginx
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
eIsDirectory
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
:
AddRedirectToWwwPermanent: reindirizza definitivamente la richiesta al
www
sottodominio se la richiesta nonwww
è. Reindirizza con un codice di stato Status308PermanentRedirect.AddRedirectToWww: reindirizzare la richiesta al
www
sottodominio se la richiesta in ingresso nonwww
è. Reindirizza con un codice di stato Status307TemporaryRedirect. Un overload consente di fornire il codice di stato per la risposta. Usare un campo della classe StatusCodes per un'assegnazione di codice di stato.
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 $2
e 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
dahttps://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:
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 |
Sì |
/my-cool-redirect-rule/1234/5678 |
Sì |
/anotherredirect-rule/1234/5678 |
Sì |
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 |
Sì |
/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. Le API del framework ASP.NET Core che utilizzano 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
, .jpg
o .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 Permanently
e 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;
}
}
}
Possibile soluzione:
- Richiesta PNG:
https://redirect6.azurewebsites.net/image.png
- Richiesta JPG:
https://redirect6.azurewebsites.net/image.jpg
Esempi di espressioni regolari
Obiettivo | 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.
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.
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:
- URL Rewrite Module for IIS in Windows Server
- Modulo Apache mod_rewrite in Apache Server
- Riscrittura URL in Nginx
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
eIsDirectory
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
:
AddRedirectToWwwPermanent: reindirizza definitivamente la richiesta al
www
sottodominio se la richiesta nonwww
è. Reindirizza con un codice di stato Status308PermanentRedirect.AddRedirectToWww: reindirizzare la richiesta al
www
sottodominio se la richiesta in ingresso nonwww
è. Reindirizza con un codice di stato Status307TemporaryRedirect. Un overload consente di specificare il codice di stato per la risposta. Usare un campo della classe StatusCodes per un'assegnazione di codice di stato.
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
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
Richiesta originale con AddRedirectToHttpsPermanent
: http://localhost:5000/secure
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
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 |
Sì |
/my-cool-redirect-rule/1234/5678 |
Sì |
/anotherredirect-rule/1234/5678 |
Sì |
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 |
Sì |
/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
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
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
, .jpg
o .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 Permanently
e 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
Richiesta originale: /image.jpg
Esempi di espressioni regolari
Obiettivo | 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.
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.
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:
- URL Rewrite Module for IIS in Windows Server
- Modulo Apache mod_rewrite in Apache Server
- Riscrittura URL in Nginx
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
eIsDirectory
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
:
AddRedirectToWwwPermanent: reindirizza definitivamente la richiesta al
www
sottodominio se la richiesta nonwww
è. Reindirizza con un codice di stato Status308PermanentRedirect.AddRedirectToWww: reindirizzare la richiesta al
www
sottodominio se la richiesta in ingresso nonwww
è. Reindirizza con un codice di stato Status307TemporaryRedirect. Un overload consente di specificare il codice di stato per la risposta. Usare un campo della classe StatusCodes per un'assegnazione di codice di stato.
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
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
Richiesta originale con AddRedirectToHttpsPermanent
: http://localhost:5000/secure
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
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 |
Sì |
/my-cool-redirect-rule/1234/5678 |
Sì |
/anotherredirect-rule/1234/5678 |
Sì |
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 |
Sì |
/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
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
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
, .jpg
o .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 Permanently
e 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
Richiesta originale: /image.jpg
Esempi di espressioni regolari
Obiettivo | 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
- Visualizzare o scaricare il codice di esempio (procedura per il download)
- Riscrivere l'origineMiddleware in GitHub
- Avvio dell'app in ASP.NET Core
- Middleware di ASP.NET Core
- Espressioni regolari in .NET
- Linguaggio di espressioni regolari - Riferimento rapido
- Modulo Apache mod_rewrite
- Using Url Rewrite Module 2.0 (for IIS) (Uso di URL Rewrite Module 2.0 per IIS)
- URL Rewrite Module Configuration Reference (Guida di riferimento per la configurazione di URL Rewrite Module)
- Keep a simple URL structure (Mantenere una struttura URL semplice)
- 10 URL Rewriting Tips and Tricks (10 suggerimenti e consigli per la riscrittura URL)
- To slash or not to slash (Uso del carattere barra)