Middleware de Reconfiguração de URL no ASP.NET Core

Por Kirk Larkin e Rick Anderson

Este artigo apresenta a reconfiguração de URL com instruções sobre como usar o Middleware de Reconfiguração de URL em aplicativos ASP.NET Core.

A reconfiguração de URL é o ato de modificar URLs de solicitação com base em uma ou mais regras predefinidas. A reconfiguração de URL cria uma abstração entre locais de recursos e seus endereços, de forma que os locais e os endereços não estejam totalmente vinculados. A reconfiguração de URL é útil em vários cenários para:

  • Mover ou substituir recursos de servidor temporária ou permanentemente e manter localizadores estáveis para esses recursos.
  • Dividir o processamento de solicitação entre diferentes aplicativos ou áreas de um aplicativo.
  • Remover, adicionar ou reorganizar segmentos de URL em solicitações de entrada.
  • Otimizar URLs públicas para SEO (Otimização do Mecanismo de Pesquisa).
  • Permitir o uso de URLs públicas amigáveis para ajudar os visitantes a prever o conteúdo retornado ao solicitar um recurso.
  • Redirecionar solicitações não seguras para pontos de extremidade seguros.
  • Impedir o hotlink, em que um site externo usa um ativo estático hospedado em outro site vinculando o ativo ao seu próprio conteúdo.

A reconfiguração de URL pode reduzir o desempenho de um aplicativo. Limite o número e a complexidade das regras.

Redirecionamento e reconfiguração de URL

A diferença entre os termos redirecionamento de URL e reconfiguração de URL é sutil, mas tem implicações importantes no fornecimento de recursos aos clientes. O Middleware de Reconfiguração de URL do ASP.NET Core pode atender às necessidades de ambos.

Um redirecionamento de URL envolve uma operação do lado do cliente, em que o cliente é instruído a acessar um recurso em um endereço diferente do que ele solicitou originalmente. Isso exige uma viagem de ida e volta para o servidor. A URL de redirecionamento retornada para o cliente é exibida na barra de endereços do navegador quando o cliente faz uma nova solicitação para o recurso.

Se /resource é redirecionado para /different-resource, o servidor responde que o cliente deve obter o recurso em /different-resource com um código de status indicando que o redirecionamento é temporário ou permanente.

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

Ao redirecionar solicitações para uma URL diferente, indique se o redirecionamento é permanente ou temporário especificando o código de status com a resposta:

  • O código de status 301 - Moved Permanently é usado quando o recurso tem uma nova URL permanente e todas as solicitações futuras para o recurso devem usar a nova URL. O cliente pode armazenar a resposta em cache e reutilizá-la quando um código de status 301 é recebido.

  • O código de status 302 - Found é usado quando o redirecionamento é temporário ou está geralmente sujeito a alterações. O código de status 302 indica para o cliente não armazenar a URL e usá-la no futuro.

Para obter mais informações sobre códigos de status, confira RFC 9110: definições de código de status.

Uma reconfiguração de URL é uma operação do servidor que fornece um recurso de um endereço de recurso diferente do que o solicitado pelo cliente. A reconfiguração de uma URL não exige uma viagem de ida e volta para o servidor. A URL reconfigurada não é retornada para o cliente e não é exibida na barra de endereços do navegador.

Se /resource é reconfigurado como /different-resource, o servidor efetua fetch internamente e retorna o recurso em /different-resource.

Embora o cliente possa ter a capacidade de recuperar o recurso na URL reconfigurada, ele não é informado de que o recurso existe na URL reconfigurada ao fazer a solicitação e receber a resposta.

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

Aplicativo de exemplo de reconfiguração de URL

Explore as funcionalidades do Middleware de Reconfiguração de URL com o aplicativo de exemplo. O aplicativo aplica as regras de redirecionamento e reconfiguração e mostra a URL redirecionada ou reconfigurada para vários cenários.

Quando usar o middleware de reconfiguração de URL

Use o Middleware de Reescrita de URL quando as seguintes abordagens não forem satisfatórias:

Use o middleware de reescrita de URL quando o aplicativo estiver hospedado no servidor HTTP.sys.

As principais razões para usar as tecnologias de reconfiguração de URL baseada em servidor no IIS, no Apache e no Nginx são:

  • O middleware não dá suporte às funcionalidades completas desses módulos.

    Algumas funcionalidades dos módulos de servidor não funcionam com projetos ASP.NET Core, como as restrições IsFile e IsDirectory do módulo de Reconfiguração do IIS. Nesses cenários, use o middleware.

  • O desempenho do middleware provavelmente não corresponde ao desempenho dos módulos.

    Os parâmetros de comparação são a única maneira de saber com certeza qual abordagem degrada mais o desempenho ou se a degradação de desempenho é insignificante.

Extensão e opções

Estabeleça regras de reconfiguração e redirecionamento de URL criando uma instância da classe RewriteOptions com métodos de extensão para cada uma das regras de reconfiguração. Encadear várias regras na ordem em que elas devem ser processadas. As RewriteOptions são passadas para o Middleware de Reconfiguração de URL, conforme ele é adicionado ao pipeline de solicitação com 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();

No código anterior, MethodRules é uma classe definida pelo usuário. Confira RewriteRules.cs neste artigo para obter mais informações.

Redirecionar não www para www

Três opções permitem que o aplicativo redirecione solicitações não wwwpara www:

  • AddRedirectToWwwPermanent: redirecionar permanentemente a solicitação para o subdomínio www se a solicitação não for www. Redireciona com um código de status Status308PermanentRedirect.

  • AddRedirectToWww: redirecionar a solicitação para o subdomínio www se a solicitação de entrada não for www. Redireciona com um código de status Status307TemporaryRedirect. Uma sobrecarga permite fornecer o código de status para a resposta. Use um campo da classe StatusCodes para uma atribuição de código de status.

Redirecionamento de URL

Use AddRedirect para redirecionar as solicitações. O primeiro parâmetro contém a Expressão Regular .NET (Regex) para correspondência no caminho da URL de entrada. O segundo parâmetro é a cadeia de caracteres de substituição. O terceiro parâmetro, se presente, especifica o código de status. Se o código de status não for especificado, ele usará como padrão 302 – Encontrado, que indica que o recurso foi substituído ou movido temporariamente.

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

Em um navegador com as ferramentas para desenvolvedores habilitadas, faça uma solicitação para o aplicativo de exemplo com o caminho /redirect-rule/1234/5678. A expressão regular corresponde ao caminho de solicitação em redirect-rule/(.*) e o caminho é substituído por /redirected/1234/5678. A URL de redirecionamento é enviada novamente ao cliente com um código de status 302 – Encontrado. O navegador faz uma nova solicitação na URL de redirecionamento, que é exibida na barra de endereços do navegador. Como não há nenhuma correspondência de regras no aplicativo de exemplo na URL de redirecionamento:

  • A segunda solicitação recebe uma resposta 200 – OK do aplicativo.
  • O corpo da resposta mostra a URL de redirecionamento.

Uma viagem de ida e volta é feita para o servidor quando uma URL é redirecionada.

Aviso

Tenha cuidado ao estabelecer regras de redirecionamento. As regras de redirecionamento são avaliadas em cada solicitação para o aplicativo, incluindo após um redirecionamento. É fácil criar acidentalmente um loop de redirecionamentos infinitos.

A parte da expressão contida nos parênteses é chamada um grupo de captura. O ponto (.) da expressão significa corresponder a qualquer caractere. O asterisco (*) indica corresponder ao caractere zero precedente ou mais vezes. Portanto, os dois últimos segmentos de caminho da URL, 1234/5678, são capturados pelo grupo de captura (.*). Qualquer valor fornecido na URL de solicitação após redirect-rule/ é capturado por esse único grupo de captura.

Na cadeia de caracteres de substituição, os grupos capturados são injetados na cadeia de caracteres com o cifrão ($) seguido do número de sequência da captura. O primeiro valor do grupo de captura é obtido com $1, o segundo com $2e eles continuam em sequência para os grupos de captura na expressão regular. Há apenas um grupo capturado na expressão regular da regra de redirecionamento no $1, para que haja apenas um grupo injetado na cadeia de caracteres de substituição, que é redirect-rule/(.*). Quando a regra é aplicada, a URL se torna /redirected/1234/5678.

Experimente /redirect-rule/1234/5678 com as ferramentas do navegador na guia rede.

Redirecionamento de URL para um ponto de extremidade seguro

Use AddRedirectToHttps para redirecionar solicitações HTTP para o mesmo host e caminho usando o protocolo HTTPS. Se o código de status não for fornecido, o middleware usará como padrão 302 – Encontrado. Se a porta não for fornecida:

  • O middleware usará como padrão null.
  • O esquema será alterado para https (protocolo HTTPS), e o cliente acessará o recurso na porta 443.

O exemplo a seguir mostra como definir o código de status como 301 - Moved Permanently e alterar a porta para a porta HTTPS usada pelo Kestrel no localhost. Em produção, a porta HTTPS é definida como nula:

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

Use AddRedirectToHttpsPermanent para redirecionar solicitações não seguras para o mesmo host e caminho com o protocolo HTTPS seguro na porta 443. O middleware define o código de status como 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();

Observação

Ao redirecionar para um ponto de extremidade seguro sem a necessidade de regras de redirecionamento adicionais, recomendamos o uso do Middleware de Redirecionamento HTTPS. Para mais informações, consulte Impor o HTTPS.

O aplicativo de exemplo demonstra como usar AddRedirectToHttps ou AddRedirectToHttpsPermanent. Faça uma solicitação HTTP não segura para o aplicativo no http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz. Ao testar o redirecionamento de HTTP para HTTPS com localhost:

  • Use a URL HTTP, que tem uma porta diferente da URL HTTPS. A URL HTTP está no arquivo Properties/launchSettings.json.
  • A remoção do s de https://localhost/{port} falha porque o localhost não responde no HTTP à porta HTTPS.

A imagem a seguir mostra a imagem das ferramentas do navegador F12 de uma solicitação para http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz usar o código anterior:

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

Reconfiguração de URL

Use AddRewrite para criar uma regra para a reconfiguração de URLs. O primeiro parâmetro contém a expressão regular para correspondência no caminho da URL de entrada. O segundo parâmetro é a cadeia de caracteres de substituição. O terceiro parâmetro, skipRemainingRules: {true|false}, indica para o middleware se ele deve ou não ignorar regras de reconfiguração adicionais se a regra atual é aplicada.

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

Experimente a solicitação para https://redirect6.azurewebsites.net/rewrite-rule/1234/5678

O acento circunflexo (^) no início da expressão significa que a correspondência começa no início do caminho da URL.

No exemplo anterior com a regra de redirecionamento, redirect-rule/(.*), não há nenhum acento circunflexo (^) no início da expressão regular. Portanto, qualquer caractere pode preceder redirect-rule/ no caminho para uma correspondência com êxito.

Caminho Corresponder a
/redirect-rule/1234/5678 Sim
/my-cool-redirect-rule/1234/5678 Sim
/anotherredirect-rule/1234/5678 Sim

A regra de reconfiguração, ^rewrite-rule/(\d+)/(\d+), corresponde apenas a caminhos se eles são iniciados com rewrite-rule/. Na tabela a seguir, observe a diferença na correspondência.

Caminho Corresponder a
/rewrite-rule/1234/5678 Sim
/my-cool-rewrite-rule/1234/5678 Não
/anotherrewrite-rule/1234/5678 Não

Após a parte ^rewrite-rule/ da expressão, há dois grupos de captura, (\d+)/(\d+). O \d significa corresponder a um dígito (número). O sinal de adição (+) significa corresponder a um ou mais caracteres anteriores. Portanto, a URL precisa conter um número seguido de uma barra "/" seguida de outro número. Esses grupos de captura são injetados na URL reconfigurada como $1 e $2. A cadeia de caracteres de substituição da regra de reconfiguração coloca os grupos capturados na cadeia de consulta. O caminho solicitado de /rewrite-rule/1234/5678 foi reescrito para obter o recurso em /rewritten?var1=1234&var2=5678. Se uma cadeia de consulta estiver presente na solicitação original, ela será preservada quando a URL for reconfigurada.

Não há nenhuma viagem de ida e volta para o servidor para retorno do recurso. Se o recurso existir, ele será buscado e retornado para o cliente com um código de status 200 – OK. Como o cliente não é redirecionado, a URL na barra de endereços do navegador não é alterada. Os clientes não conseguem detectar que uma operação de reconfiguração de URL ocorreu no servidor.

Dicas de desempenho para reescrita e redirecionamento de URL

Para a resposta mais rápida:

  • Ordene as regras de reconfiguração da regra com correspondência mais frequente para a regra com correspondência menos frequente.
  • Use skipRemainingRules: true sempre que possível, porque as regras de correspondência são computacionalmente caras e aumentam o tempo de resposta do aplicativo. Ignore o processamento das regras restantes quando ocorrer uma correspondência e nenhum processamento de regra adicional for necessário.

Aviso

Um usuário mal-intencionado pode fornecer entrada para RegularExpressions, causando um ataque de negação de serviço. APIs ASP.NET Core Framework que usam RegularExpressions passam um tempo limite. Por exemplo, as classes RedirectRule e RewriteRule passam um tempo limite de um segundo.

mod_rewrite do Apache

Aplique as regras do mod_rewrite do Apache com AddApacheModRewrite. Verifique se o arquivo de regras foi implantado com o aplicativo. Para obter mais informações e exemplos de regras de mod_rewrite, consulte mod_rewrite do Apache.

Um StreamReader é usado para ler as regras do arquivo de regras ApacheModRewrite.txt:

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

O aplicativo de exemplo redireciona solicitações de /apache-mod-rules-redirect/(.\*) para /redirected?id=$1. O código de status da resposta é 302 – Encontrado.

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

Experimente a solicitação para https://redirect6.azurewebsites.net/apache-mod-rules-redirect/1234

O middleware do Apache dá suporte às seguintes variáveis de servidor do mod_rewrite do Apache:

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

Regras do Módulo de Reconfiguração de URL do IIS

Para usar o mesmo conjunto de regras que se aplica ao Módulo de Reconfiguração de URL do IIS, use AddIISUrlRewrite. Verifique se o arquivo de regras foi implantado com o aplicativo. Não instrua o middleware a usar o arquivo web.config do aplicativo quando ele estiver em execução no IIS do Windows Server. Com o IIS, essas regras devem ser armazenadas fora do arquivo web.config do aplicativo para evitar conflitos com o módulo de Reconfiguração do IIS. Para obter mais informações e exemplos de regras do Módulo de Reconfiguração de URL do IIS, consulte Usando o Módulo de Reconfiguração de URL 2.0 e Referência de configuração do Módulo de Reconfiguração de URL.

Um StreamReader é usado para ler as regras do arquivo de regras IISUrlRewrite.xml:

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

O aplicativo de exemplo reconfigura as solicitações de /iis-rules-rewrite/(.*) para /rewritten?id=$1. A resposta é enviada ao cliente com um código de status 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>

Experimente a solicitação para https://redirect6.azurewebsites.net/iis-rules-rewrite/xyz

Aplicativos que têm um Módulo de Reescrita do IIS ativo com regras de nível de servidor configuradas que afetam o aplicativo de maneiras indesejáveis:

Recursos sem suporte

O middleware não dá suporte aos seguintes recursos do Módulo de Reconfiguração de URL do IIS:

  • Regras de saída
  • Variáveis de servidor personalizadas
  • Curingas
  • LogRewrittenUrl

Variáveis de servidor compatíveis

O middleware dá suporte às seguintes variáveis de servidor do Módulo de Reconfiguração de URL do IIS:

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

IFileProvider pode ser obtido por meio de uma PhysicalFileProvider. Essa abordagem pode fornecer maior flexibilidade para o local dos arquivos de regras de reconfiguração. Verifique se os arquivos de regras de reconfiguração são implantados no servidor no caminho fornecido.

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

Regra baseada em método

Use Add para implementar a lógica de regra personalizada em um método. Add expõe o RewriteContext, que disponibiliza o HttpContext para uso nos métodos de redirecionamento. A propriedade RewriteContext.Result determina como o processamento de pipeline adicional é manipulado. Defina o valor como um dos campos RuleResult descritos na tabela a seguir.

Resultado do contexto de reescrita Ação
RuleResult.ContinueRules (padrão) Continuar aplicando regras.
RuleResult.EndResponse Parar de aplicar regras e enviar a resposta.
RuleResult.SkipRemainingRules Parar de aplicar regras e enviar o contexto para o próximo middleware.
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();

O aplicativo de exemplo demonstra um método que redireciona as solicitações para caminhos que terminam com .xml. Quando uma solicitação é feita para /file.xml:

  • A solicitação é redirecionada para /xmlfiles/file.xml
  • O código status é definido como 301 - Moved Permanently. Quando o navegador faz uma nova solicitação para /xmlfiles/file.xml, o Middleware de Arquivo Estático fornece o arquivo para o cliente por meio da pasta wwwroot/xmlfiles. Para um redirecionamento, defina explicitamente o código de status da resposta. Caso contrário, um código de status 200 – OK será retornado e o redirecionamento não ocorrerá no cliente.

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

Essa abordagem também pode reconfigurar as solicitações. O aplicativo de exemplo demonstra a reconfiguração do caminho de qualquer solicitação de arquivo de texto para fornecer o arquivo de texto file.txt por meio da pasta wwwroot. O Middleware de Arquivo Estático fornece o arquivo com base no caminho de solicitação atualizado:

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

Regra baseada em IRule

Use Add para usar a lógica de regra em uma classe que implementa a interface IRule. IRule fornece maior flexibilidade em comparação ao uso da abordagem de regra baseada em método. A classe de implementação pode incluir um construtor, que permite passar parâmetros para o método ApplyRule.

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

Os valores dos parâmetros no aplicativo de exemplo para a extension e o newPath são verificados para atender a várias condições. A extension precisa conter um valor que precisa ser .png, .jpg ou .gif. Se o newPath não é válido, uma ArgumentException é gerada. Se uma solicitação for feita para image.png, ela será redirecionada para /png-images/image.png. Se uma solicitação for feita para image.jpg, ela será redirecionada para /jpg-images/image.jpg. O código de status é definido como 301 - Moved Permanently e o context.Result é definida para parar o processamento de regras e enviar a resposta.

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

Experimente:

  • Solicitação PNG: https://redirect6.azurewebsites.net/image.png
  • Solicitação JPG: https://redirect6.azurewebsites.net/image.jpg

Exemplos do regex

Goal Cadeia de caracteres do regex &
Exemplo de correspondência
Cadeia de caracteres de substituição &
Exemplo de saída
Reconfigurar o caminho na cadeia de consulta ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Barra "/" à direita da faixa ^path2/(.*)/$
/path2/xyz/
$1
/path2/xyz
Impor barra "/" à direita ^path3/(.*[^/])$
/path3/xyz
$1/
/path3/xyz/
Evitar a reconfiguração de solicitações específicas ^(.*)(?<!\.axd)$ ou
^(?!.*\.axd$)(.*)$
Sim: /path4/resource.htm
Não: /path4/resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Reorganizar segmentos de URL path5/(.*)/(.*)/(.*)
path5/1/2/3
path5/$3/$2/$1
path5/3/2/1
Substituir um segmento de URL ^path6/(.*)/segment2/(.*)
^path6/segment1/segment2/segment3
path6/$1/replaced/$2
/path6/segment1/replaced/segment3

Os links na tabela anterior usam o seguinte código implantado no 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();

Na maioria dos exemplos de expressão regular anteriores, o literal path é usado para fazer regras de reescrita testáveis exclusivas para o exemplo implantado. Normalmente, a expressão regular não incluiria path. Por exemplo, confira estas tabelas de exemplos de expressão regular .

Este documento apresenta a reconfiguração de URL com instruções sobre como usar o Middleware de Reconfiguração de URL em aplicativos ASP.NET Core.

A reconfiguração de URL é o ato de modificar URLs de solicitação com base em uma ou mais regras predefinidas. A reconfiguração de URL cria uma abstração entre locais de recursos e seus endereços, de forma que os locais e os endereços não estejam totalmente vinculados. A reconfiguração de URL é útil em vários cenários para:

  • Mover ou substituir recursos de servidor temporária ou permanentemente e manter localizadores estáveis para esses recursos.
  • Dividir o processamento de solicitação entre diferentes aplicativos ou áreas de um aplicativo.
  • Remover, adicionar ou reorganizar segmentos de URL em solicitações de entrada.
  • Otimizar URLs públicas para SEO (Otimização do Mecanismo de Pesquisa).
  • Permitir o uso de URLs públicas amigáveis para ajudar os visitantes a prever o conteúdo retornado ao solicitar um recurso.
  • Redirecionar solicitações não seguras para pontos de extremidade seguros.
  • Impedir o hotlink, em que um site externo usa um ativo estático hospedado em outro site vinculando o ativo ao seu próprio conteúdo.

Observação

A reconfiguração de URL pode reduzir o desempenho de um aplicativo. Sempre que possível, limite o número e a complexidade das regras.

Exibir ou baixar código de exemplo (como baixar)

Redirecionamento e reconfiguração de URL

A diferença entre os termos redirecionamento de URL e reconfiguração de URL é sutil, mas tem implicações importantes no fornecimento de recursos aos clientes. O Middleware de Reconfiguração de URL do ASP.NET Core pode atender às necessidades de ambos.

Um redirecionamento de URL envolve uma operação do lado do cliente, em que o cliente é instruído a acessar um recurso em um endereço diferente do que ele solicitou originalmente. Isso exige uma viagem de ida e volta para o servidor. A URL de redirecionamento retornada para o cliente é exibida na barra de endereços do navegador quando o cliente faz uma nova solicitação para o recurso.

Se /resource é redirecionado para /different-resource, o servidor responde que o cliente deve obter o recurso em /different-resource com um código de status indicando que o redirecionamento é temporário ou permanente.

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

Ao redirecionar solicitações para uma URL diferente, indique se o redirecionamento é permanente ou temporário especificando o código de status com a resposta:

  • O código de status 301 - Moved Permanently é usado quando o recurso tem uma nova URL permanente e você deseja instruir o cliente que todas as solicitações futuras para o recurso devem usar a nova URL. O cliente pode armazenar a resposta em cache e reutilizá-la quando um código de status 301 é recebido.

  • O código de status 302 – Encontrado é usado quando o redirecionamento é temporário ou está geralmente sujeito a alterações. O código de status 302 indica para o cliente não armazenar a URL e usá-la no futuro.

Para obter mais informações sobre códigos de status, confira RFC 9110: definições de código de status.

Uma reconfiguração de URL é uma operação do servidor que fornece um recurso de um endereço de recurso diferente do que o solicitado pelo cliente. A reconfiguração de uma URL não exige uma viagem de ida e volta para o servidor. A URL reconfigurada não é retornada para o cliente e não é exibida na barra de endereços do navegador.

Se /resource é reconfigurado como /different-resource, o servidor efetua fetch internamente e retorna o recurso em /different-resource.

Embora o cliente possa ter a capacidade de recuperar o recurso na URL reconfigurada, ele não é informado de que o recurso existe na URL reconfigurada ao fazer a solicitação e receber a resposta.

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

Aplicativo de exemplo de reconfiguração de URL

Explore as funcionalidades do Middleware de Reconfiguração de URL com o aplicativo de exemplo. O aplicativo aplica as regras de redirecionamento e reconfiguração e mostra a URL redirecionada ou reconfigurada para vários cenários.

Quando usar o middleware de reconfiguração de URL

Use o Middleware de Reconfiguração de URL quando não for possível usar as seguintes abordagens:

Use o middleware de reescrita de URL quando o aplicativo estiver hospedado no servidor HTTP.sys.

As principais razões para usar as tecnologias de reconfiguração de URL baseada em servidor no IIS, no Apache e no Nginx são:

  • O middleware não dá suporte às funcionalidades completas desses módulos.

    Algumas funcionalidades dos módulos de servidor não funcionam com projetos ASP.NET Core, como as restrições IsFile e IsDirectory do módulo de Reconfiguração do IIS. Nesses cenários, use o middleware.

  • O desempenho do middleware provavelmente não corresponde ao desempenho dos módulos.

    Os parâmetros de comparação são a única maneira de saber com certeza qual abordagem degrada mais o desempenho ou se a degradação de desempenho é insignificante.

Pacote

O Middleware de Reconfiguração de URL é fornecido pelo pacote Microsoft.AspNetCore.Rewrite, que é incluído implicitamente em aplicativos ASP.NET Core.

Extensão e opções

Estabeleça regras de reconfiguração e redirecionamento de URL criando uma instância da classe RewriteOptions com métodos de extensão para cada uma das regras de reconfiguração. Encadeie várias regras na ordem em que deseja que sejam processadas. As RewriteOptions são passadas para o Middleware de Reconfiguração de URL, conforme ele é adicionado ao pipeline de solicitação com 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}"));
}

Redirecionar não www para www

Três opções permitem que o aplicativo redirecione solicitações não wwwpara www:

  • AddRedirectToWwwPermanent: redirecionar permanentemente a solicitação para o subdomínio www se a solicitação não for www. Redireciona com um código de status Status308PermanentRedirect.

  • AddRedirectToWww: redirecionar a solicitação para o subdomínio www se a solicitação de entrada não for www. Redireciona com um código de status Status307TemporaryRedirect. Uma sobrecarga permite que você forneça o código de status para a resposta. Use um campo da classe StatusCodes para uma atribuição de código de status.

Redirecionamento de URL

Use AddRedirect para redirecionar as solicitações. O primeiro parâmetro contém o Regex para correspondência no caminho da URL de entrada. O segundo parâmetro é a cadeia de caracteres de substituição. O terceiro parâmetro, se presente, especifica o código de status. Se você não especificar o código de status, ele usará como padrão 302 – Encontrado, que indica que o recurso foi substituído ou movido temporariamente.

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

Em um navegador com as ferramentas para desenvolvedores habilitadas, faça uma solicitação para o aplicativo de exemplo com o caminho /redirect-rule/1234/5678. O regex corresponde ao caminho de solicitação em redirect-rule/(.*) e o caminho é substituído por /redirected/1234/5678. A URL de redirecionamento é enviada novamente ao cliente com um código de status 302 – Encontrado. O navegador faz uma nova solicitação na URL de redirecionamento, que é exibida na barra de endereços do navegador. Como não há nenhuma correspondência de regras no aplicativo de exemplo na URL de redirecionamento:

  • A segunda solicitação recebe uma resposta 200 – OK do aplicativo.
  • O corpo da resposta mostra a URL de redirecionamento.

Uma viagem de ida e volta é feita para o servidor quando uma URL é redirecionada.

Aviso

Tenha cuidado ao estabelecer regras de redirecionamento. As regras de redirecionamento são avaliadas em cada solicitação para o aplicativo, incluindo após um redirecionamento. É fácil criar acidentalmente um loop de redirecionamentos infinitos.

Solicitação original: /redirect-rule/1234/5678

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

A parte da expressão contida nos parênteses é chamada um grupo de captura. O ponto (.) da expressão significa corresponder a qualquer caractere. O asterisco (*) indica corresponder ao caractere zero precedente ou mais vezes. Portanto, os dois últimos segmentos de caminho da URL, 1234/5678, são capturados pelo grupo de captura (.*). Qualquer valor que você fornecer na URL de solicitação após redirect-rule/ é capturado por esse único grupo de captura.

Na cadeia de caracteres de substituição, os grupos capturados são injetados na cadeia de caracteres com o cifrão ($) seguido do número de sequência da captura. O primeiro valor de grupo de captura é obtido com $1, o segundo com $2 e eles continuam em sequência para os grupos de captura no regex. Há apenas um grupo capturado no regex da regra de redirecionamento no aplicativo de exemplo, para que haja apenas um grupo injetado na cadeia de caracteres de substituição, que é $1. Quando a regra é aplicada, a URL se torna /redirected/1234/5678.

Redirecionamento de URL para um ponto de extremidade seguro

Use AddRedirectToHttps para redirecionar solicitações HTTP para o mesmo host e caminho usando o protocolo HTTPS. Se o código de status não for fornecido, o middleware usará como padrão 302 – Encontrado. Se a porta não for fornecida:

  • O middleware usará como padrão null.
  • O esquema será alterado para https (protocolo HTTPS), e o cliente acessará o recurso na porta 443.

O exemplo a seguir mostra como definir o código de status como 301 - Moved Permanently e alterar a porta para 5001.

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

    app.UseRewriter(options);
}

Use AddRedirectToHttpsPermanent para redirecionar solicitações não seguras para o mesmo host e caminho com o protocolo HTTPS seguro na porta 443. O middleware define o código de status como 301 - Moved Permanently.

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

    app.UseRewriter(options);
}

Observação

Ao redirecionar para um ponto de extremidade seguro sem a necessidade de regras de redirecionamento adicionais, recomendamos o uso do Middleware de Redirecionamento HTTPS. Para obter mais informações, veja o tópico Impor HTTPS.

O aplicativo de exemplo pode demonstrar como usar AddRedirectToHttps ou AddRedirectToHttpsPermanent. Adicione o método de extensão às RewriteOptions. Faça uma solicitação não segura para o aplicativo em qualquer URL. Ignore o aviso de segurança do navegador de que o certificado autoassinado não é confiável ou crie uma exceção para confiar no certificado.

Solicitação original usando AddRedirectToHttps(301, 5001): http://localhost:5000/secure

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

Solicitação original usando AddRedirectToHttpsPermanent: http://localhost:5000/secure

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

Reconfiguração de URL

Use AddRewrite para criar uma regra para a reconfiguração de URLs. O primeiro parâmetro contém o regex para correspondência no caminho da URL de entrada. O segundo parâmetro é a cadeia de caracteres de substituição. O terceiro parâmetro, skipRemainingRules: {true|false}, indica para o middleware se ele deve ou não ignorar regras de reconfiguração adicionais se a regra atual é aplicada.

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

Solicitação original: /rewrite-rule/1234/5678

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

O acento circunflexo (^) no início da expressão significa que a correspondência começa no início do caminho da URL.

No exemplo anterior com a regra de redirecionamento, redirect-rule/(.*), não há nenhum acento circunflexo (^) no início do regex. Portanto, qualquer caractere pode preceder redirect-rule/ no caminho para uma correspondência com êxito.

Caminho Corresponder a
/redirect-rule/1234/5678 Sim
/my-cool-redirect-rule/1234/5678 Sim
/anotherredirect-rule/1234/5678 Sim

A regra de reconfiguração, ^rewrite-rule/(\d+)/(\d+), corresponde apenas a caminhos se eles são iniciados com rewrite-rule/. Na tabela a seguir, observe a diferença na correspondência.

Caminho Corresponder a
/rewrite-rule/1234/5678 Sim
/my-cool-rewrite-rule/1234/5678 Não
/anotherrewrite-rule/1234/5678 Não

Após a parte ^rewrite-rule/ da expressão, há dois grupos de captura, (\d+)/(\d+). O \d significa corresponder a um dígito (número). O sinal de adição (+) significa corresponder a um ou mais caracteres anteriores. Portanto, a URL precisa conter um número seguido de uma barra "/" seguida de outro número. Esses grupos de captura são injetados na URL reconfigurada como $1 e $2. A cadeia de caracteres de substituição da regra de reconfiguração coloca os grupos capturados na cadeia de consulta. O caminho solicitado de /rewrite-rule/1234/5678 foi reconfigurado para obter o recurso em /rewritten?var1=1234&var2=5678. Se uma cadeia de consulta estiver presente na solicitação original, ela será preservada quando a URL for reconfigurada.

Não há nenhuma viagem de ida e volta para o servidor para obtenção do recurso. Se o recurso existir, ele será buscado e retornado para o cliente com um código de status 200 – OK. Como o cliente não é redirecionado, a URL na barra de endereços do navegador não é alterada. Os clientes não conseguem detectar que uma operação de reconfiguração de URL ocorreu no servidor.

Observação

Use skipRemainingRules: true sempre que possível, porque as regras de correspondência são computacionalmente caras e aumentam o tempo de resposta do aplicativo. Para a resposta mais rápida do aplicativo:

  • Ordene as regras de reconfiguração da regra com correspondência mais frequente para a regra com correspondência menos frequente.
  • Ignore o processamento das regras restantes quando ocorrer uma correspondência e nenhum processamento de regra adicional for necessário.

mod_rewrite do Apache

Aplique as regras do mod_rewrite do Apache com AddApacheModRewrite. Verifique se o arquivo de regras foi implantado com o aplicativo. Para obter mais informações e exemplos de regras de mod_rewrite, consulte mod_rewrite do Apache.

Um StreamReader é usado para ler as regras do arquivo de regras ApacheModRewrite.txt:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

O aplicativo de exemplo redireciona solicitações de /apache-mod-rules-redirect/(.\*) para /redirected?id=$1. O código de status da resposta é 302 – Encontrado.

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

Solicitação original: /apache-mod-rules-redirect/1234

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

O middleware dá suporte às seguintes variáveis de servidor do mod_rewrite do Apache:

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

Regras do Módulo de Reconfiguração de URL do IIS

Para usar o mesmo conjunto de regras que se aplica ao Módulo de Reconfiguração de URL do IIS, use AddIISUrlRewrite. Verifique se o arquivo de regras foi implantado com o aplicativo. Não instrua o middleware a usar o arquivo web.config do aplicativo quando ele estiver em execução no IIS do Windows Server. Com o IIS, essas regras devem ser armazenadas fora do arquivo web.config do aplicativo para evitar conflitos com o módulo de Reconfiguração do IIS. Para obter mais informações e exemplos de regras do Módulo de Reconfiguração de URL do IIS, consulte Usando o Módulo de Reconfiguração de URL 2.0 e Referência de configuração do Módulo de Reconfiguração de URL.

Um StreamReader é usado para ler as regras do arquivo de regras IISUrlRewrite.xml:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

O aplicativo de exemplo reconfigura as solicitações de /iis-rules-rewrite/(.*) para /rewritten?id=$1. A resposta é enviada ao cliente com um código de status 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>

Solicitação original: /iis-rules-rewrite/1234

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

Caso você tenha um Módulo de Reconfiguração do IIS ativo com regras no nível do servidor configuradas que poderiam afetar o aplicativo de maneiras indesejadas, desabilite o Módulo de Reconfiguração do IIS em um aplicativo. Para obter mais informações, consulte Desabilitando módulos do IIS.

Recursos sem suporte

O middleware não dá suporte aos seguintes recursos do Módulo de Reconfiguração de URL do IIS:

  • Regras de saída
  • Variáveis de servidor personalizadas
  • Curingas
  • LogRewrittenUrl

Variáveis de servidor compatíveis

O middleware dá suporte às seguintes variáveis de servidor do Módulo de Reconfiguração de URL do IIS:

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

Observação

Também obtenha um IFileProvider por meio de um PhysicalFileProvider. Essa abordagem pode fornecer maior flexibilidade para o local dos arquivos de regras de reconfiguração. Verifique se os arquivos de regras de reconfiguração são implantados no servidor no caminho fornecido.

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

Regra baseada em método

Use Add para implementar sua própria lógica de regra em um método. Add expõe o RewriteContext, que disponibiliza o HttpContext para uso no método. O RewriteContext.Result determina como o processamento adicional de pipeline é feito. Defina o valor como um dos campos RuleResult descritos na tabela a seguir.

Resultado do contexto de reescrita Ação
RuleResult.ContinueRules (padrão) Continuar aplicando regras.
RuleResult.EndResponse Parar de aplicar regras e enviar a resposta.
RuleResult.SkipRemainingRules Parar de aplicar regras e enviar o contexto para o próximo middleware.
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}"));
}

O aplicativo de exemplo demonstra um método que redireciona as solicitações para caminhos que terminam com .xml. Se uma solicitação for feita para /file.xml, ela será redirecionada para /xmlfiles/file.xml. O código status é definido como 301 - Moved Permanently. Quando o navegador faz uma nova solicitação para /xmlfiles/file.xml, o Middleware de Arquivo Estático fornece o arquivo para o cliente por meio da pasta wwwroot/xmlfiles. Para um redirecionamento, defina explicitamente o código de status da resposta. Caso contrário, um código de status 200 – OK será retornado e o redirecionamento não ocorrerá no cliente.

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

Essa abordagem também pode reconfigurar as solicitações. O aplicativo de exemplo demonstra a reconfiguração do caminho de qualquer solicitação de arquivo de texto para fornecer o arquivo de texto file.txt por meio da pasta wwwroot. O Middleware de Arquivo Estático fornece o arquivo com base no caminho de solicitação atualizado:

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

Regra baseada em IRule

Use Add para usar a lógica de regra em uma classe que implementa a interface IRule. IRule fornece maior flexibilidade em comparação ao uso da abordagem de regra baseada em método. A classe de implementação pode incluir um construtor, que permite passar parâmetros para o método 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}"));
}

Os valores dos parâmetros no aplicativo de exemplo para a extension e o newPath são verificados para atender a várias condições. A extension precisa conter um valor que precisa ser .png, .jpg ou .gif. Se o newPath não é válido, uma ArgumentException é gerada. Se uma solicitação for feita para image.png, ela será redirecionada para /png-images/image.png. Se uma solicitação for feita para image.jpg, ela será redirecionada para /jpg-images/image.jpg. O código de status é definido como 301 - Moved Permanently e o context.Result é definida para parar o processamento de regras e enviar a resposta.

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

Solicitação original: /image.png

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

Solicitação original: /image.jpg

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

Exemplos do regex

Goal Cadeia de caracteres do regex &
Exemplo de correspondência
Cadeia de caracteres de substituição &
Exemplo de saída
Reconfigurar o caminho na cadeia de consulta ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Barra "/" à direita da faixa (.*)/$
/path/
$1
/path
Impor barra "/" à direita (.*[^/])$
/path
$1/
/path/
Evitar a reconfiguração de solicitações específicas ^(.*)(?<!\.axd)$ ou ^(?!.*\.axd$)(.*)$
Sim: /resource.htm
Não: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Reorganizar segmentos de URL path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Substituir um segmento de URL ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

Este documento apresenta a reconfiguração de URL com instruções sobre como usar o Middleware de Reconfiguração de URL em aplicativos ASP.NET Core.

A reconfiguração de URL é o ato de modificar URLs de solicitação com base em uma ou mais regras predefinidas. A reconfiguração de URL cria uma abstração entre locais de recursos e seus endereços, de forma que os locais e os endereços não estejam totalmente vinculados. A reconfiguração de URL é útil em vários cenários para:

  • Mover ou substituir recursos de servidor temporária ou permanentemente e manter localizadores estáveis para esses recursos.
  • Dividir o processamento de solicitação entre diferentes aplicativos ou áreas de um aplicativo.
  • Remover, adicionar ou reorganizar segmentos de URL em solicitações de entrada.
  • Otimizar URLs públicas para SEO (Otimização do Mecanismo de Pesquisa).
  • Permitir o uso de URLs públicas amigáveis para ajudar os visitantes a prever o conteúdo retornado ao solicitar um recurso.
  • Redirecionar solicitações não seguras para pontos de extremidade seguros.
  • Impedir o hotlink, em que um site externo usa um ativo estático hospedado em outro site vinculando o ativo ao seu próprio conteúdo.

Observação

A reconfiguração de URL pode reduzir o desempenho de um aplicativo. Sempre que possível, limite o número e a complexidade das regras.

Exibir ou baixar código de exemplo (como baixar)

Redirecionamento e reconfiguração de URL

A diferença entre os termos redirecionamento de URL e reconfiguração de URL é sutil, mas tem implicações importantes no fornecimento de recursos aos clientes. O Middleware de Reconfiguração de URL do ASP.NET Core pode atender às necessidades de ambos.

Um redirecionamento de URL envolve uma operação do lado do cliente, em que o cliente é instruído a acessar um recurso em um endereço diferente do que ele solicitou originalmente. Isso exige uma viagem de ida e volta para o servidor. A URL de redirecionamento retornada para o cliente é exibida na barra de endereços do navegador quando o cliente faz uma nova solicitação para o recurso.

Se /resource é redirecionado para /different-resource, o servidor responde que o cliente deve obter o recurso em /different-resource com um código de status indicando que o redirecionamento é temporário ou permanente.

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

Ao redirecionar solicitações para uma URL diferente, indique se o redirecionamento é permanente ou temporário especificando o código de status com a resposta:

  • O código de status 301 - Moved Permanently é usado quando o recurso tem uma nova URL permanente e você deseja instruir o cliente que todas as solicitações futuras para o recurso devem usar a nova URL. O cliente pode armazenar a resposta em cache e reutilizá-la quando um código de status 301 é recebido.

  • O código de status 302 – Encontrado é usado quando o redirecionamento é temporário ou está geralmente sujeito a alterações. O código de status 302 indica para o cliente não armazenar a URL e usá-la no futuro.

Para obter mais informações sobre códigos de status, confira RFC 9110: definições de código de status.

Uma reconfiguração de URL é uma operação do servidor que fornece um recurso de um endereço de recurso diferente do que o solicitado pelo cliente. A reconfiguração de uma URL não exige uma viagem de ida e volta para o servidor. A URL reconfigurada não é retornada para o cliente e não é exibida na barra de endereços do navegador.

Se /resource é reconfigurado como /different-resource, o servidor efetua fetch internamente e retorna o recurso em /different-resource.

Embora o cliente possa ter a capacidade de recuperar o recurso na URL reconfigurada, ele não é informado de que o recurso existe na URL reconfigurada ao fazer a solicitação e receber a resposta.

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

Aplicativo de exemplo de reconfiguração de URL

Explore as funcionalidades do Middleware de Reconfiguração de URL com o aplicativo de exemplo. O aplicativo aplica as regras de redirecionamento e reconfiguração e mostra a URL redirecionada ou reconfigurada para vários cenários.

Quando usar o Middleware de Reconfiguração de URL

Use o Middleware de Reconfiguração de URL quando não for possível usar as seguintes abordagens:

Além disso, use o middleware quando o aplicativo estiver hospedado no servidor HTTP.sys (anteriormente chamado WebListener).

As principais razões para usar as tecnologias de reconfiguração de URL baseada em servidor no IIS, no Apache e no Nginx são:

  • O middleware não dá suporte às funcionalidades completas desses módulos.

    Algumas funcionalidades dos módulos de servidor não funcionam com projetos ASP.NET Core, como as restrições IsFile e IsDirectory do módulo de Reconfiguração do IIS. Nesses cenários, use o middleware.

  • O desempenho do middleware provavelmente não corresponde ao desempenho dos módulos.

    Os parâmetros de comparação são a única maneira de saber com certeza qual abordagem degrada mais o desempenho ou se a degradação de desempenho é insignificante.

Pacote

Para incluir o middleware em seu projeto, adicione uma referência de pacote ao metapacote Microsoft.AspNetCore.App no arquivo de projeto, que contém o pacote Microsoft.AspNetCore.Rewrite.

Quando não estiver usando o metapacote Microsoft.AspNetCore.App, adicione uma referência de projeto ao pacote Microsoft.AspNetCore.Rewrite.

Extensão e opções

Estabeleça regras de reconfiguração e redirecionamento de URL criando uma instância da classe RewriteOptions com métodos de extensão para cada uma das regras de reconfiguração. Encadeie várias regras na ordem em que deseja que sejam processadas. As RewriteOptions são passadas para o Middleware de Reconfiguração de URL, conforme ele é adicionado ao pipeline de solicitação com 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}"));
}

Redirecionar não www para www

Três opções permitem que o aplicativo redirecione solicitações não wwwpara www:

  • AddRedirectToWwwPermanent: redirecionar permanentemente a solicitação para o subdomínio www se a solicitação não for www. Redireciona com um código de status Status308PermanentRedirect.

  • AddRedirectToWww: redirecionar a solicitação para o subdomínio www se a solicitação de entrada não for www. Redireciona com um código de status Status307TemporaryRedirect. Uma sobrecarga permite que você forneça o código de status para a resposta. Use um campo da classe StatusCodes para uma atribuição de código de status.

Redirecionamento de URL

Use AddRedirect para redirecionar as solicitações. O primeiro parâmetro contém o regex para correspondência no caminho da URL de entrada. O segundo parâmetro é a cadeia de caracteres de substituição. O terceiro parâmetro, se presente, especifica o código de status. Se você não especificar o código de status, ele usará como padrão 302 – Encontrado, que indica que o recurso foi substituído ou movido temporariamente.

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

Em um navegador com as ferramentas para desenvolvedores habilitadas, faça uma solicitação para o aplicativo de exemplo com o caminho /redirect-rule/1234/5678. O regex corresponde ao caminho de solicitação em redirect-rule/(.*) e o caminho é substituído por /redirected/1234/5678. A URL de redirecionamento é enviada novamente ao cliente com um código de status 302 – Encontrado. O navegador faz uma nova solicitação na URL de redirecionamento, que é exibida na barra de endereços do navegador. Como não há nenhuma correspondência de regras no aplicativo de exemplo na URL de redirecionamento:

  • A segunda solicitação recebe uma resposta 200 – OK do aplicativo.
  • O corpo da resposta mostra a URL de redirecionamento.

Uma viagem de ida e volta é feita para o servidor quando uma URL é redirecionada.

Aviso

Tenha cuidado ao estabelecer regras de redirecionamento. As regras de redirecionamento são avaliadas em cada solicitação para o aplicativo, incluindo após um redirecionamento. É fácil criar acidentalmente um loop de redirecionamentos infinitos.

Solicitação original: /redirect-rule/1234/5678

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

A parte da expressão contida nos parênteses é chamada um grupo de captura. O ponto (.) da expressão significa corresponder a qualquer caractere. O asterisco (*) indica corresponder ao caractere zero precedente ou mais vezes. Portanto, os dois últimos segmentos de caminho da URL, 1234/5678, são capturados pelo grupo de captura (.*). Qualquer valor que você fornecer na URL de solicitação após redirect-rule/ é capturado por esse único grupo de captura.

Na cadeia de caracteres de substituição, os grupos capturados são injetados na cadeia de caracteres com o cifrão ($) seguido do número de sequência da captura. O primeiro valor de grupo de captura é obtido com $1, o segundo com $2 e eles continuam em sequência para os grupos de captura no regex. Há apenas um grupo capturado no regex da regra de redirecionamento no aplicativo de exemplo, para que haja apenas um grupo injetado na cadeia de caracteres de substituição, que é $1. Quando a regra é aplicada, a URL se torna /redirected/1234/5678.

Redirecionamento de URL para um ponto de extremidade seguro

Use AddRedirectToHttps para redirecionar solicitações HTTP para o mesmo host e caminho usando o protocolo HTTPS. Se o código de status não for fornecido, o middleware usará como padrão 302 – Encontrado. Se a porta não for fornecida:

  • O middleware usará como padrão null.
  • O esquema será alterado para https (protocolo HTTPS), e o cliente acessará o recurso na porta 443.

O exemplo a seguir mostra como definir o código de status como 301 - Moved Permanently e alterar a porta para 5001.

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

    app.UseRewriter(options);
}

Use AddRedirectToHttpsPermanent para redirecionar solicitações não seguras para o mesmo host e caminho com o protocolo HTTPS seguro na porta 443. O middleware define o código de status como 301 - Moved Permanently.

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

    app.UseRewriter(options);
}

Observação

Ao redirecionar para um ponto de extremidade seguro sem a necessidade de regras de redirecionamento adicionais, recomendamos o uso do Middleware de Redirecionamento HTTPS. Para obter mais informações, veja o tópico Impor HTTPS.

O aplicativo de exemplo pode demonstrar como usar AddRedirectToHttps ou AddRedirectToHttpsPermanent. Adicione o método de extensão às RewriteOptions. Faça uma solicitação não segura para o aplicativo em qualquer URL. Ignore o aviso de segurança do navegador de que o certificado autoassinado não é confiável ou crie uma exceção para confiar no certificado.

Solicitação original usando AddRedirectToHttps(301, 5001): http://localhost:5000/secure

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

Solicitação original usando AddRedirectToHttpsPermanent: http://localhost:5000/secure

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

Reconfiguração de URL

Use AddRewrite para criar uma regra para a reconfiguração de URLs. O primeiro parâmetro contém o regex para correspondência no caminho da URL de entrada. O segundo parâmetro é a cadeia de caracteres de substituição. O terceiro parâmetro, skipRemainingRules: {true|false}, indica para o middleware se ele deve ou não ignorar regras de reconfiguração adicionais se a regra atual é aplicada.

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

Solicitação original: /rewrite-rule/1234/5678

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

O acento circunflexo (^) no início da expressão significa que a correspondência começa no início do caminho da URL.

No exemplo anterior com a regra de redirecionamento, redirect-rule/(.*), não há nenhum acento circunflexo (^) no início do regex. Portanto, qualquer caractere pode preceder redirect-rule/ no caminho para uma correspondência com êxito.

Caminho Corresponder a
/redirect-rule/1234/5678 Sim
/my-cool-redirect-rule/1234/5678 Sim
/anotherredirect-rule/1234/5678 Sim

A regra de reconfiguração, ^rewrite-rule/(\d+)/(\d+), corresponde apenas a caminhos se eles são iniciados com rewrite-rule/. Na tabela a seguir, observe a diferença na correspondência.

Caminho Corresponder a
/rewrite-rule/1234/5678 Sim
/my-cool-rewrite-rule/1234/5678 Não
/anotherrewrite-rule/1234/5678 Não

Após a parte ^rewrite-rule/ da expressão, há dois grupos de captura, (\d+)/(\d+). O \d significa corresponder a um dígito (número). O sinal de adição (+) significa corresponder a um ou mais caracteres anteriores. Portanto, a URL precisa conter um número seguido de uma barra "/" seguida de outro número. Esses grupos de captura são injetados na URL reconfigurada como $1 e $2. A cadeia de caracteres de substituição da regra de reconfiguração coloca os grupos capturados na cadeia de consulta. O caminho solicitado de /rewrite-rule/1234/5678 foi reconfigurado para obter o recurso em /rewritten?var1=1234&var2=5678. Se uma cadeia de consulta estiver presente na solicitação original, ela será preservada quando a URL for reconfigurada.

Não há nenhuma viagem de ida e volta para o servidor para obtenção do recurso. Se o recurso existir, ele será buscado e retornado para o cliente com um código de status 200 – OK. Como o cliente não é redirecionado, a URL na barra de endereços do navegador não é alterada. Os clientes não conseguem detectar que uma operação de reconfiguração de URL ocorreu no servidor.

Observação

Use skipRemainingRules: true sempre que possível, porque as regras de correspondência são computacionalmente caras e aumentam o tempo de resposta do aplicativo. Para a resposta mais rápida do aplicativo:

  • Ordene as regras de reconfiguração da regra com correspondência mais frequente para a regra com correspondência menos frequente.
  • Ignore o processamento das regras restantes quando ocorrer uma correspondência e nenhum processamento de regra adicional for necessário.

mod_rewrite do Apache

Aplique as regras do mod_rewrite do Apache com AddApacheModRewrite. Verifique se o arquivo de regras foi implantado com o aplicativo. Para obter mais informações e exemplos de regras de mod_rewrite, consulte mod_rewrite do Apache.

Um StreamReader é usado para ler as regras do arquivo de regras ApacheModRewrite.txt:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

O aplicativo de exemplo redireciona solicitações de /apache-mod-rules-redirect/(.\*) para /redirected?id=$1. O código de status da resposta é 302 – Encontrado.

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

Solicitação original: /apache-mod-rules-redirect/1234

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

O middleware dá suporte às seguintes variáveis de servidor do mod_rewrite do Apache:

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

Regras do Módulo de Reconfiguração de URL do IIS

Para usar o mesmo conjunto de regras que se aplica ao Módulo de Reconfiguração de URL do IIS, use AddIISUrlRewrite. Verifique se o arquivo de regras foi implantado com o aplicativo. Não instrua o middleware a usar o arquivo web.config do aplicativo quando ele estiver em execução no IIS do Windows Server. Com o IIS, essas regras devem ser armazenadas fora do arquivo web.config do aplicativo para evitar conflitos com o módulo de Reconfiguração do IIS. Para obter mais informações e exemplos de regras do Módulo de Reconfiguração de URL do IIS, consulte Usando o Módulo de Reconfiguração de URL 2.0 e Referência de configuração do Módulo de Reconfiguração de URL.

Um StreamReader é usado para ler as regras do arquivo de regras IISUrlRewrite.xml:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

O aplicativo de exemplo reconfigura as solicitações de /iis-rules-rewrite/(.*) para /rewritten?id=$1. A resposta é enviada ao cliente com um código de status 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>

Solicitação original: /iis-rules-rewrite/1234

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

Caso você tenha um Módulo de Reconfiguração do IIS ativo com regras no nível do servidor configuradas que poderiam afetar o aplicativo de maneiras indesejadas, desabilite o Módulo de Reconfiguração do IIS em um aplicativo. Para obter mais informações, consulte Desabilitando módulos do IIS.

Recursos sem suporte

O middleware liberado com o ASP.NET Core 2.x não dá suporte aos seguintes recursos do Módulo de Reconfiguração de URL do IIS:

  • Regras de saída
  • Variáveis de servidor personalizadas
  • Curingas
  • LogRewrittenUrl

Variáveis de servidor compatíveis

O middleware dá suporte às seguintes variáveis de servidor do Módulo de Reconfiguração de URL do IIS:

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

Observação

Também obtenha um IFileProvider por meio de um PhysicalFileProvider. Essa abordagem pode fornecer maior flexibilidade para o local dos arquivos de regras de reconfiguração. Verifique se os arquivos de regras de reconfiguração são implantados no servidor no caminho fornecido.

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

Regra baseada em método

Use Add para implementar sua própria lógica de regra em um método. Add expõe o RewriteContext, que disponibiliza o HttpContext para uso no método. O RewriteContext.Result determina como o processamento adicional de pipeline é feito. Defina o valor como um dos campos RuleResult descritos na tabela a seguir.

Resultado do contexto de reescrita Ação
RuleResult.ContinueRules (padrão) Continuar aplicando regras.
RuleResult.EndResponse Parar de aplicar regras e enviar a resposta.
RuleResult.SkipRemainingRules Parar de aplicar regras e enviar o contexto para o próximo middleware.
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}"));
}

O aplicativo de exemplo demonstra um método que redireciona as solicitações para caminhos que terminam com .xml. Se uma solicitação for feita para /file.xml, ela será redirecionada para /xmlfiles/file.xml. O código status é definido como 301 - Moved Permanently. Quando o navegador faz uma nova solicitação para /xmlfiles/file.xml, o Middleware de Arquivo Estático fornece o arquivo para o cliente por meio da pasta wwwroot/xmlfiles. Para um redirecionamento, defina explicitamente o código de status da resposta. Caso contrário, um código de status 200 – OK será retornado e o redirecionamento não ocorrerá no cliente.

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

Essa abordagem também pode reconfigurar as solicitações. O aplicativo de exemplo demonstra a reconfiguração do caminho de qualquer solicitação de arquivo de texto para fornecer o arquivo de texto file.txt por meio da pasta wwwroot. O Middleware de Arquivo Estático fornece o arquivo com base no caminho de solicitação atualizado:

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

Regra baseada em IRule

Use Add para usar a lógica de regra em uma classe que implementa a interface IRule. IRule fornece maior flexibilidade em comparação ao uso da abordagem de regra baseada em método. A classe de implementação pode incluir um construtor, que permite passar parâmetros para o método 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}"));
}

Os valores dos parâmetros no aplicativo de exemplo para a extension e o newPath são verificados para atender a várias condições. A extension precisa conter um valor que precisa ser .png, .jpg ou .gif. Se o newPath não é válido, uma ArgumentException é gerada. Se uma solicitação for feita para image.png, ela será redirecionada para /png-images/image.png. Se uma solicitação for feita para image.jpg, ela será redirecionada para /jpg-images/image.jpg. O código de status é definido como 301 - Moved Permanently e o context.Result é definida para parar o processamento de regras e enviar a resposta.

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

Solicitação original: /image.png

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

Solicitação original: /image.jpg

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

Exemplos do regex

Goal Cadeia de caracteres do regex &
Exemplo de correspondência
Cadeia de caracteres de substituição &
Exemplo de saída
Reconfigurar o caminho na cadeia de consulta ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Barra "/" à direita da faixa (.*)/$
/path/
$1
/path
Impor barra "/" à direita (.*[^/])$
/path
$1/
/path/
Evitar a reconfiguração de solicitações específicas ^(.*)(?<!\.axd)$ ou ^(?!.*\.axd$)(.*)$
Sim: /resource.htm
Não: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Reorganizar segmentos de URL path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Substituir um segmento de URL ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

Recursos adicionais