ПО промежуточной обработки для перезаписи URL-адресов в ASP.NET Core

Note

Это не последняя версия этой статьи. В текущей версии см. версию .NET 10 этой статьи.

Warning

Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущей версии см. версию .NET 10 этой статьи.

Авторы: Кирк Ларкин (Kirk Larkin) и Рик Андерсон (Rick Anderson)

Эта статья содержит вводные сведения о переопределении URL-адресов и инструкции по использованию ПО промежуточного слоя для переопределения URL-адресов в приложениях ASP.NET Core.

Переопределение URL-адресов представляет собой изменение URL-адресов запросов на основе одного или нескольких предопределенных правил. Переопределение URL-адресов создает абстракцию между расположениями ресурсов и их адресами, позволяя убрать тесную связь между ними. Существует несколько сценариев, где может пригодиться переопределение URL-адресов:

  • Временное или постоянное перемещение или замещение ресурсов сервера с сохранением стабильных указателей для этих ресурсов.
  • Разделение обработки запросов между разными приложениями или разными областями одного приложения.
  • Удаление, добавление или переупорядочение сегментов URL-адресов для входящих запросов.
  • Оптимизация общедоступных URL-адресов в целях оптимизации для поисковых систем (SEO).
  • Разрешение использования понятных общедоступных URL-адресов, чтобы помочь посетителям прогнозировать содержимое, возвращаемое в результате запроса ресурса.
  • Перенаправление небезопасных запросов на защищенные конечные точки.
  • Запрет вставки прямых ссылок, когда внешний сайт использует статический ресурс, размещенный на другом сайте, привязывая ресурс к своему содержимому.

Переопределение URL-адресов может снижать производительность приложения. Ограничьте количество и сложность правил.

Перенаправление и переопределение URL-адресов

Разница между перенаправлением и переопределением URL-адресов может показаться незначительной, но она оказывает существенное влияние на предоставление ресурсов клиентам. ПО промежуточного слоя для переопределения URL-адресов в ASP.NET Core удовлетворяет потребность в обеих этих функциях.

Перенаправление URL-адресов является операцией на стороне клиента, которая предписывает клиенту обратиться к ресурсу по другому адресу, отличному от запрошенного клиентом. Для этого используется круговое обращение к серверу. URL-адрес перенаправления, возвращаемый клиенту, отображается в адресной строке браузера, когда клиент отправляет новый запрос для данного ресурса.

Если /resourceперенаправляется на /different-resource, сервер отвечает, что клиенту следует получить ресурс в /different-resource с кодом состояния, указывающим, что такое перенаправление является временным или постоянным.

Конечная точка службы WebAPI была временно изменена с версии 1 (v1) на версию 2 (v2) на сервере. Клиент делает запрос к службе по пути версии 1 /v1/api. Сервер отправляет ответ 302 (Обнаружено) с новым временным путем для службы версии 2 /v2/api. Клиент делает второй запрос к службе по URL-адресу перенаправления. Сервер отвечает кодом состояния 200 (OK).

При перенаправлении запросов на другой URL-адрес можно указать, является ли оно постоянным или временным, предоставив код состояния в ответе:

  • Код состояния 301 - Moved Permanently используется, когда ресурс имеет новый постоянный URL-адрес и все последующие запросы для этого ресурса должны использовать новый URL-адрес. Клиент может кэшировать и повторно использовать отклик при получении кода состояния 301.

  • Код 302 - Found состояния используется, когда перенаправление является временным или обычно подлежит изменению. Код состояния 302 указывает клиенту, что не нужно сохранять URL-адрес и использовать его в будущем.

Дополнительные сведения о кодах состояния см. в статье RFC 9110: определения кода состояния.

Переопределение URL-адреса является операцией на стороне сервера для предоставления ресурса с другого адреса ресурса, отличного от запрошенного клиентом. Переопределение URL-адреса не требует кругового обращения к серверу. Переопределенный URL-адрес не возвращается клиенту и не отображается в адресной строке браузера.

Если /resourceперезаписывается в /different-resource, сервер внутренне получает и возвращает ресурс по адресу /different-resource.

Хотя клиент может быть в состоянии получить ресурс по переопределенному URL-адресу, когда клиент отправляет запрос и получает отклик, он не уведомляется о наличии ресурса по переопределенному URL-адресу.

На сервере конечная точка службы WebAPI была изменена с версии 1 (v1) на версию 2 (v2). Клиент делает запрос к службе по пути /v1/api версии 1. URL-адрес запроса переписывается для доступа к службе по пути версии 2 /v2/api. Служба отвечает клиенту кодом состояния 200 (OK).

Пример приложения с переопределением URL-адресов

Ознакомьтесь с функциями компонента Middleware для перезаписи URL-адресов с помощью примерного приложения. Это приложение применяет правила перенаправления и переопределения и показывает перенаправленный или переопределенный URL-адрес для нескольких сценариев.

Когда использовать ПО промежуточного слоя для перезаписи URL-адресов

Используйте промежуточное ПО для перезаписи URL-адресов, если следующие подходы вас не устраивают:

Используйте ПО промежуточного слоя для переопределения URL, когда приложение размещено на сервере HTTP.sys.

Основные причины использовать технологии перезаписи URL-адресов на стороне сервера в IIS, Apache и Nginx:

  • ПО промежуточного слоя не поддерживает все функции этих модулей.

    Некоторые функции серверных модулей не работают с проектами ASP.NET Core, например ограничения IsFile и IsDirectory для модуля переопределения IIS. В этих случаях следует использовать ПО промежуточного слоя.

  • Производительность ПО промежуточного слоя, скорее всего, не соответствует производительности модулей.

    Тестирование производительности — это единственный способ узнать точно, какой подход больше всего снижает производительность и является ли такое снижение незначительным.

Расширение и параметры

Задайте правила перезаписи и перенаправления URL-адресов, создав экземпляр класса RewriteOptions с методами расширения для каждого из правил перезаписи. Объедините в цепочку несколько правил в том порядке, в котором они должны быть обработаны. RewriteOptions передаются компоненту-посреднику для переопределения URL-адресов при его добавлении в конвейер обработки запросов с помощью 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();

В приведенном выше коде MethodRules — это определяемый пользователем класс. Дополнительные сведения см. в разделе RewriteRules.cs этой статьи.

Перенаправить адрес без www на адрес с www

Три параметра разрешают приложению перенаправлять запросы, отличные от www, на www:

  • AddRedirectToWwwPermanent: постоянно перенаправлять запрос на поддомен www, если запрос не относится к www. Перенаправляет с кодом состояния Status308PermanentRedirect.

  • AddRedirectToWww: перенаправьте запрос на поддомен www, если входящий запрос не является www. Перенаправляет, используя код состояния Status307TemporaryRedirect. Перегрузка позволяет предоставить код состояния для ответа. Используйте поле класса StatusCodes для назначения кода состояния.

Перенаправление URL-адреса

Используйте AddRedirect для перенаправления запросов. Первый параметр содержит регулярное выражение .NET (Regex) для сопоставления с путем входящего URL-адреса. Второй параметр — строка замены. Третий параметр (при его наличии) указывает код состояния. Если код состояния не задан, по умолчанию используется код 302 — Found (найдено), указывающий, что ресурс временно перемещен или заменен.

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

В браузере с включёнными средствами разработчика выполните запрос к тестовому приложению по пути /redirect-rule/1234/5678. Регулярное выражение сопоставляется с путём запроса в redirect-rule/(.*), а затем этот путь заменяется на /redirected/1234/5678. URL-адрес перенаправления отправляется обратно клиенту с кодом состояния 302 (найдено). Браузер выполняет новый запрос на URL-адрес перенаправления, отображаемый в адресной строке. Поскольку в примере приложения нет правил, соответствующих URL-адресу перенаправления:

  • Второй запрос получает от приложения ответ 200 (ОК).
  • Текст ответа показывает URL-адрес перенаправления.

При перенаправлении URL-адреса используется круговое обращение к серверу.

Warning

Соблюдайте осторожность при задании правил перенаправления. Правила перенаправления проверяются при каждом запросе к приложению, в том числе после перенаправления. Можно легко случайно создать бесконечный цикл перенаправлений.

Часть выражения, заключенная в скобки, называется группой записи. Точка (.) в выражении означает совпадение с любым символом. Звёздочка (*) означает, что предыдущий символ может встречаться ноль или более раз. Таким образом, два последних сегмента пути URL-адреса, 1234/5678, захватываются группой захвата (.*). Любое значение, указанное в URL-адресе запроса после redirect-rule/, перехватывается этой группой записи.

В строке замены захваченные группы подставляются в строку с помощью знака доллара ($), за которым следует порядковый номер захваченной группы. Первое значение группы записи можно получить с помощью $1, а второе — с помощью $2. После этого эти значения по очереди используются для групп записи в регулярном выражении. В регулярном выражении правила перенаправления в redirect-rule/(.*) есть только одна группа захвата, поэтому в строке замены подставляется только одна группа — $1. Когда применяется правило, URL-адрес становится /redirected/1234/5678.

Попробуйте /redirect-rule/1234/5678 в инструментах разработчика браузера на вкладке «Сеть».

Перенаправление URL-адреса на защищенную конечную точку

Используйте AddRedirectToHttps, чтобы перенаправлять HTTP-запросы на тот же узел и путь с использованием протокола HTTPS. Если код состояния не указан, ПО промежуточного слоя по умолчанию использует значение 302 (найдено). Если порт не указан:

  • Для промежуточного ПО по умолчанию используется значение null.
  • Схема меняется на https (протокол HTTPS), и клиент обращается к ресурсу через порт 443.

В следующем примере показано, как задать код 301 - Moved Permanently состояния и изменить порт на порт HTTPS, используемый Kestrel на localhost. В рабочей среде порт HTTPS имеет значение NULL:

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

Используйте AddRedirectToHttpsPermanent, чтобы перенаправить небезопасные запросы на тот же узел и путь с использованием безопасного протокола HTTPS через порт 443. ПО промежуточного слоя задает код состояния 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();

Note

Если при перенаправлении на защищённый конечный пункт не требуются дополнительные правила перенаправления, мы рекомендуем использовать компонент middleware для перенаправления на HTTPS. Дополнительные сведения см. в разделе Принудительное использование HTTPS.

В этом примере приложения показано, как использовать AddRedirectToHttps или AddRedirectToHttpsPermanent. Выполните небезопасный HTTP-запрос к приложению по адресу http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz. При проверке перенаправления с HTTP на HTTPS с использованием localhost:

  • Используйте URL-адрес HTTP с портом, который отличается от порта URL-адреса HTTPS. URL-адрес HTTP находится в файле Properties/launchSettings.json.
  • При удалении s из https://localhost/{port} происходит сбой, так как localhost не отвечает на HTTP на порту HTTPS.

На следующем изображении показан запрос к http://redirect6.azurewebsites.net/iis-rules-rewrite/xyz в инструментах разработчика браузера (F12) с использованием приведенного выше кода:

Окно браузера, в котором средства разработчика отслеживают запросы и отклики: добавление перенаправления на HTTPS

URL rewrite

Используйте AddRewrite, чтобы создать правило для переопределения URL-адресов. Первый параметр содержит регулярное выражение, соответствующее пути входящего URL-адреса. Второй параметр — строка замены. Третий параметр, skipRemainingRules: {true|false}, указывает промежуточному программному обеспечению, следует ли пропускать дополнительные правила перезаписи, если применяется текущее правило.

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

Попробуйте повторить запрос к https://redirect6.azurewebsites.net/rewrite-rule/1234/5678.

Символ вставки (^) в начале выражения означает, что сопоставление начинается с начала пути URL.

В предыдущем примере с правилом перенаправления, redirect-rule/(.*), в начале регулярного выражения отсутствует символ ^ (^). Таким образом, для успешного совпадения в пути перед redirect-rule/ могут находиться любые символы.

Path Match
/redirect-rule/1234/5678 Yes
/my-cool-redirect-rule/1234/5678 Yes
/anotherredirect-rule/1234/5678 Yes

Правило переопределения ^rewrite-rule/(\d+)/(\d+) соответствует путям, только если они начинаются с rewrite-rule/. В следующей таблице обратите внимание на разницу в сопоставлении.

Path Match
/rewrite-rule/1234/5678 Yes
/my-cool-rewrite-rule/1234/5678 No
/anotherrewrite-rule/1234/5678 No

После части выражения ^rewrite-rule/ следуют две группы захвата (\d+)/(\d+). \d означает соответствие цифре (числу). Знак "плюс" (+) означает соответствие одному или нескольким предшествующим символам. Таким образом, URL-адрес должен содержать число, за которым следует слэш, а затем другое число. Эти группы захвата подставляются в перезаписанный URL-адрес как $1 и $2. Строка замены для правила перезаписи помещает захваченные группы в строку запроса. Запрошенный путь /rewrite-rule/1234/5678 переопределяется, чтобы ресурс можно было получить по адресу /rewritten?var1=1234&var2=5678. Если в исходном запросе присутствует строка запроса, она сохраняется при переопределении URL-адреса.

Чтобы вернуть ресурс, не требуется дополнительный запрос к серверу. Если ресурс существует, он извлекается и возвращается клиенту с кодом состояния 200 (ОК). Так как клиент не перенаправляется, URL-адрес в адресной строке браузера не изменяется. Клиенты не могут узнать, что на сервере произошла операция переопределения URL-адреса.

Советы по повышению производительности при перезаписи URL-адресов и перенаправлении

Чтобы максимально ускорить отклик:

  • Расположите правила перезаписи в порядке от наиболее часто срабатывающего правила к наименее часто срабатывающему.
  • Используйте skipRemainingRules: true при любой возможности, так как правила сопоставления потребляют много ресурсов и ухудшают время отклика приложения. Пропускать обработку остальных правил, если найдено совпадение и дополнительная обработка правил не требуется.

Warning

Злоумышленник может предоставлять дорогостоящие входные данные для обработки, вызывая RegularExpressionsатаку типа "отказ в обслуживании". ASP.NET API-интерфейсы платформы Core, использующие RegularExpressions время ожидания. Например, время ожидания Regex (_regexTimeout) класса RedirectRule и классом RewriteRule передаются в односекундное время ожидания.

Note

Ссылки в документации на исходный код .NET обычно загружают ветку репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для конкретного релиза, используйте раскрывающийся список Переключение ветвей или тегов. Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Apache mod_rewrite (модуль для перезаписи URL на веб-сервере Apache)

Для применения правил mod_rewrite Apache можно использовать AddApacheModRewrite. Убедитесь, что файл правил развертывается вместе с приложением. Дополнительные сведения и примеры правил mod_rewrite см. в статье о правилах mod_rewrite Apache.

StreamReader используется для чтения правил из файла 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();

Пример приложения перенаправляет запросы из /apache-mod-rules-redirect/(.\*) в /redirected?id=$1. Код состояния ответа: 302 - Found.

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

Попробуйте повторить запрос к https://redirect6.azurewebsites.net/apache-mod-rules-redirect/1234.

Промежуточное ПО Apache поддерживает следующие серверные переменные Apache mod_rewrite:

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

Note

Ссылки в документации на исходный код .NET обычно загружают ветку репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для конкретного релиза, используйте раскрывающийся список Переключение ветвей или тегов. Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Правила модуля переопределения URL-адресов для IIS

Чтобы использовать тот же набор правил, который применяется к модулю переопределения URL-адресов для IIS, используйте AddIISUrlRewrite. Убедитесь, что файл правил развертывается вместе с приложением. Не настраивайте промежуточное ПО на использование файла web.config приложения при работе в IIS на Windows Server. В IIS эти правила нужно хранить за пределами файла приложения web.config, чтобы предотвратить конфликты с модулем переопределения для IIS. Дополнительные сведения и примеры правил модуля переопределения URL-адресов для IIS см. в разделах Использование модуля переопределения URL-адресов 2.0 и Справочник по конфигурации модуля переопределения URL-адресов.

Используется StreamReader для чтения правил из 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();

Пример приложения переопределяет запросы с /iis-rules-rewrite/(.*) на /rewritten?id=$1. Клиенту отправляется отклик с кодом состояния 200 (ОК).

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

Попробуйте повторить запрос к https://redirect6.azurewebsites.net/iis-rules-rewrite/xyz.

Приложения с активным модулем переопределения IIS с настроенными правилами на уровне сервера, которые нежелательным образом влияют на приложение:

  • Рассмотрите возможность отключения модуля IIS URL Rewrite для этого приложения.
  • Дополнительные сведения см. в разделе Отключение модулей IIS.

Неподдерживаемые функции

ПО промежуточного слоя не поддерживает следующие функции в модуле переопределения URL-адресов для служб IIS:

  • Правила для исходящего трафика
  • Пользовательские переменные сервера
  • Wildcards
  • LogRewrittenUrl

Поддерживаемые переменные сервера

ПО промежуточного слоя поддерживает следующие переменные сервера в модуле переопределения URL-адресов для 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

Note

Ссылки в документации на исходный код .NET обычно загружают ветку репозитория по умолчанию, которая представляет текущую разработку для следующего выпуска .NET. Чтобы выбрать тег для конкретного релиза, используйте раскрывающийся список Переключение ветвей или тегов. Дополнительные сведения см. в статье Выбор тега версии исходного кода ASP.NET Core (dotnet/AspNetCore.Docs #26205).

IFileProvider можно получить с помощью PhysicalFileProvider. Такой подход может обеспечить большую гибкость в выборе расположения файлов правил перезаписи. Убедитесь, что файлы правил перезаписи развернуты на сервере по указанному пути.

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

Правило на основе метода

Используйте Add, чтобы реализовать настраиваемую логику правил в методе. Add предоставляет RewriteContext, делая возможным использование HttpContext в методах переопределения. Свойство RewriteContext.Result определяет, как осуществляется дополнительная обработка в конвейере. Установите значение одного из полей RuleResult из следующей таблицы.

Результат перезаписи контекста Action
RuleResult.ContinueRules (по умолчанию) Продолжение применения правил.
RuleResult.EndResponse Остановка применения правил и отправка отклика.
RuleResult.SkipRemainingRules Прекратите применять правила и передайте контекст следующему промежуточному обработчику.
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();

Приложение-пример демонстрирует способ, который перенаправляет запросы к путям, которые заканчиваются на .xml. Когда запрос выполняется для /file.xml:

  • Запрос перенаправляется в /xmlfiles/file.xml.
  • Код состояния получает значение 301 - Moved Permanently. Когда браузер отправляет новый запрос для /xmlfiles/file.xml, промежуточное ПО для статических файлов обслуживает файл клиенту из папки wwwroot/xmlfiles. Для перенаправления необходимо явно указать код состояния ответа. В противном случае возвращается код состояния 200 (ОК) и перенаправление на стороне клиента не происходит.

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

Этот подход также переопределяет запросы. В примере приложения показано переопределение пути для любого запроса текстового файла, чтобы отправить текстовый файл file.txt из папки wwwroot. ПО промежуточного слоя статических файлов предоставляет файл по обновленному пути запроса:

using Microsoft.AspNetCore.Rewrite;
using RewriteRules;

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

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

    app.UseRewriter(options);
}

app.UseStaticFiles();

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

app.Run();

RewriteRules.cs:

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

    if (request.Path.Value != null &&
        request.Path.Value.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
    {
        context.Result = RuleResult.SkipRemainingRules;
        request.Path = "/file.txt";
    }
}

Правило на основе IRule

Используйте Add, чтобы использовать собственную логику правил в классе, реализующем интерфейс IRule. IRule позволяет более гибко применять правила, основанные на методах. Класс реализации может включать конструктор, который позволяет передавать параметры для метода 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();

Значения параметров в примере приложения для extension и newPath проверяются на соответствие нескольким условиям. В extension должно содержаться значение .png, .jpg или .gif. Если newPath недопустим, возникает исключение ArgumentException. Если запрос выполняется для image.png, запрос перенаправляется к /png-images/image.png. Если запрос выполняется для image.jpg, запрос перенаправляется к /jpg-images/image.jpg. Для кода состояния устанавливается значение 301 - Moved Permanently, а также задается значение context.Result, чтобы остановить обработку правил и отправить ответ.

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

Try:

  • Запрос PNG: https://redirect6.azurewebsites.net/image.png
  • Запрос JPG: https://redirect6.azurewebsites.net/image.jpg

Примеры регулярных выражений

Goal Пример строки регулярного выражения
Пример сопоставления
Строка замены &
Пример вывода
Переопределение пути в строке запроса ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Удалить завершающий слеш ^path2/(.*)/$
/path2/xyz/
$1
/path2/xyz
Добавление косой черты в конце ^path3/(.*[^/])$
/path3/xyz
$1/
/path3/xyz/
Избегайте переписывания конкретных запросов ^(.*)(?<!\.axd)$ или
^(?!.*\.axd$)(.*)$
Да: /path4/resource.htm
Нет: /path4/resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Переупорядочение сегментов URL-адреса path5/(.*)/(.*)/(.*)
path5/1/2/3
path5/$3/$2/$1
path5/3/2/1
Замена сегмента URL-адреса ^path6/(.*)/segment2/(.*)
^path6/segment1/segment2/segment3
path6/$1/replaced/$2
/path6/segment1/replaced/segment3

В ссылках в предыдущей таблице используется следующий код, развернутый в 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();

В большинстве приведенных выше примеров регулярных выражений литерал path используется для создания уникальных тестируемых правил переопределения для развернутого примера. Обычно регулярное выражение не содержит path. Например, см. таблицу с примерами регулярных выражений.

Этот документ содержит вводные сведения о переопределении URL-адресов и инструкции по использованию ПО промежуточного слоя для переопределения URL-адресов в приложениях ASP.NET Core.

Переопределение URL-адресов представляет собой изменение URL-адресов запросов на основе одного или нескольких предопределенных правил. Переопределение URL-адресов создает абстракцию между расположениями ресурсов и их адресами, позволяя убрать тесную связь между ними. Существует несколько сценариев, где может пригодиться переопределение URL-адресов:

  • Временное или постоянное перемещение или замещение ресурсов сервера с сохранением стабильных указателей для этих ресурсов.
  • Разделение обработки запросов между разными приложениями или разными областями одного приложения.
  • Удаление, добавление или переупорядочение сегментов URL-адресов для входящих запросов.
  • Оптимизация общедоступных URL-адресов в целях оптимизации для поисковых систем (SEO).
  • Разрешение использования понятных общедоступных URL-адресов, чтобы помочь посетителям прогнозировать содержимое, возвращаемое в результате запроса ресурса.
  • Перенаправление небезопасных запросов на защищенные конечные точки.
  • Запрет вставки прямых ссылок, когда внешний сайт использует статический ресурс, размещенный на другом сайте, привязывая ресурс к своему содержимому.

Note

Переопределение URL-адресов может снижать производительность приложения. Следует по возможности ограничить число и сложность правил.

Просмотреть или скачать образец кода (описание загрузки)

Перенаправление и переопределение URL-адресов

Разница между перенаправлением и переопределением URL-адресов может показаться незначительной, но она оказывает существенное влияние на предоставление ресурсов клиентам. ПО промежуточного слоя для переопределения URL-адресов в ASP.NET Core удовлетворяет потребность в обеих этих функциях.

Перенаправление URL-адресов является операцией на стороне клиента, которая предписывает клиенту обратиться к ресурсу по другому адресу, отличному от запрошенного клиентом. Для этого используется круговое обращение к серверу. URL-адрес перенаправления, возвращаемый клиенту, отображается в адресной строке браузера, когда клиент отправляет новый запрос для данного ресурса.

Если /resourceперенаправляется на /different-resource, сервер отвечает, что клиенту следует получить ресурс в /different-resource с кодом состояния, указывающим, что такое перенаправление является временным или постоянным.

Конечная точка службы WebAPI была временно изменена с версии 1 (v1) на версию 2 (v2) на сервере. Клиент делает запрос к службе по пути версии 1 /v1/api. Сервер отправляет ответ 302 (Обнаружено) с новым временным путем для службы версии 2 /v2/api. Клиент делает второй запрос к службе по URL-адресу перенаправления. Сервер отвечает кодом состояния 200 (OK).

При перенаправлении запросов на другой URL-адрес можно указать, является ли оно постоянным или временным, предоставив код состояния в ответе:

  • Код состояния 301 - Moved Permanently используется, когда ресурс имеет новый постоянный URL-адрес и вы хотите сообщить клиенту, что все последующие запросы для этого ресурса должны использовать новый URL-адрес. Клиент может кэшировать и повторно использовать отклик при получении кода состояния 301.

  • Код состояния 302 (найдено) используется, когда перенаправление является временным или может меняться. Код состояния 302 указывает клиенту, что не нужно сохранять URL-адрес и использовать его в будущем.

Дополнительные сведения о кодах состояния см. в статье RFC 9110: определения кода состояния.

Переопределение URL-адреса является операцией на стороне сервера для предоставления ресурса с другого адреса ресурса, отличного от запрошенного клиентом. Переопределение URL-адреса не требует кругового обращения к серверу. Переопределенный URL-адрес не возвращается клиенту и не отображается в адресной строке браузера.

Если /resourceперезаписывается в /different-resource, сервер на внутреннем уровне получает и возвращает ресурс по адресу /different-resource.

Хотя клиент может быть в состоянии получить ресурс по переопределенному URL-адресу, когда клиент отправляет запрос и получает отклик, он не уведомляется о наличии ресурса по переопределенному URL-адресу.

На сервере конечная точка службы WebAPI была изменена с версии 1 (v1) на версию 2 (v2). Клиент делает запрос к службе по пути /v1/api версии 1. URL-адрес запроса переписывается для доступа к службе по пути версии 2 /v2/api. Служба отвечает клиенту кодом состояния 200 (OK).

Пример приложения с переопределением URL-адресов

Вы можете изучить возможности компонента промежуточного ПО для перезаписи URL-адресов с помощью примерного приложения. Это приложение применяет правила перенаправления и переопределения и показывает перенаправленный или переопределенный URL-адрес для нескольких сценариев.

Когда использовать промежуточное ПО для перезаписи URL-адресов

Используйте ПО промежуточного слоя для переопределения URL-адресов, если невозможно использовать следующие подходы:

Используйте ПО промежуточного слоя для перезаписи URL, когда приложение размещается на сервере HTTP.sys.

Основные причины использования технологий перезаписи URL-адресов на стороне сервера в IIS, Apache и Nginx:

  • ПО промежуточного слоя не поддерживает все функции этих модулей.

    Некоторые функции серверных модулей не работают с проектами ASP.NET Core, например ограничения IsFile и IsDirectory для модуля переопределения IIS. В этих случаях следует использовать ПО промежуточного слоя.

  • Производительность ПО промежуточного слоя, скорее всего, не соответствует производительности модулей.

    Тестирование производительности — это единственный способ узнать точно, какой подход больше всего снижает производительность или является ли такое снижение незначительным.

Package

ПО промежуточного слоя перезаписи URL-адресов предоставляется пакетом Microsoft.AspNetCore.Rewrite, который неявно включается в приложения ASP.NET Core.

Расширение и параметры

Настройте правила перезаписи и перенаправления URL-адресов, создав экземпляр класса RewriteOptions и используя методы расширения для каждого из правил перезаписи. Несколько правил можно объединить в цепочку в том порядке, в котором они должны обрабатываться. RewriteOptions передаются в ПО промежуточного слоя для переопределения URL-адресов по мере его добавления в конвейер запросов с помощью 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}"));
}

Перенаправить адреса без www на www

Три параметра разрешают приложению перенаправлять запросы, отличные от www, на www:

  • AddRedirectToWwwPermanent: Постоянно перенаправлять запрос на поддомен www, если запрос не относится к типу www. Перенаправляет, используя код состояния Status308PermanentRedirect.

  • AddRedirectToWww: Перенаправьте запрос на поддомен www, если входящий запрос не www. Перенаправляет с кодом состояния Status307TemporaryRedirect. Перегрузка позволяет указать код состояния в ответе. Используйте поле класса StatusCodes для назначения кода состояния.

Перенаправление URL-адреса

Используйте AddRedirect для перенаправления запросов. Первый параметр содержит регулярное выражение, соответствующее пути входящего URL-адреса. Второй параметр — строка замены. Третий параметр (при его наличии) указывает код состояния. Если код состояния не задан, по умолчанию используется код 302 (найдено), указывающий, что ресурс временно перемещен или заменен.

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

В браузере с включёнными инструментами разработчика отправьте запрос к тестовому приложению по пути /redirect-rule/1234/5678. Регулярное выражение соответствует пути запроса в redirect-rule/(.*), и этот путь заменяется на /redirected/1234/5678. URL-адрес перенаправления отправляется обратно клиенту с кодом состояния 302 (найдено). Браузер выполняет новый запрос на URL-адрес перенаправления, отображаемый в адресной строке. Поскольку в примере приложения нет правил, соответствующих URL-адресу перенаправления:

  • Второй запрос получает от приложения ответ 200 (ОК).
  • Текст ответа показывает URL-адрес перенаправления.

При перенаправлении URL-адреса используется круговое обращение к серверу.

Warning

Соблюдайте осторожность при задании правил перенаправления. Правила перенаправления проверяются при каждом запросе к приложению, в том числе после перенаправления. Можно легко случайно создать бесконечный цикл перенаправлений.

Исходный запрос: /redirect-rule/1234/5678

Окно браузера, в котором средства разработчика отслеживают запросы и отклики: добавление перенаправления

Часть выражения, заключенная в скобки, называется группой записи. Точка (.) в выражении означает совпадение с любым символом. Звездочка (*) обозначает повторение предыдущего символа ноль или более раз. Таким образом, два последних сегмента пути URL-адреса, 1234/5678, захватываются группой захвата (.*). Любое значение, указанное в URL-адресе запроса после redirect-rule/, перехватывается этой группой записи.

В строке замены захваченные группы подставляются в строку с помощью знака доллара ($), за которым следует порядковый номер захвата. Первое значение группы записи получается с помощью $1, второе — с помощью $2, после чего они продолжают по очереди использоваться для групп записи в регулярном выражении. В регулярном выражении правила перенаправления в приложении-примере есть только одна захватывающая группа, поэтому в строку замены подставляется только одна группа — $1. Когда применяется правило, URL-адрес становится /redirected/1234/5678.

Перенаправление URL-адреса на защищенную конечную точку

Используйте AddRedirectToHttps, чтобы перенаправлять HTTP-запросы на тот же узел и путь с использованием протокола HTTPS. Если код состояния не указан, ПО промежуточного слоя по умолчанию использует значение 302 (найдено). Если порт не указан:

  • Для промежуточного ПО по умолчанию используется значение null.
  • Схема меняется на https (протокол HTTPS), и клиент обращается к ресурсу через порт 443.

В следующем примере показано, как задать код 301 - Moved Permanently состояния и изменить порт на 5001.

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

    app.UseRewriter(options);
}

Используйте AddRedirectToHttpsPermanent, чтобы перенаправить небезопасные запросы на тот же узел и путь с использованием безопасного протокола HTTPS через порт 443. ПО промежуточного слоя задает код состояния 301 - Moved Permanently.

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

    app.UseRewriter(options);
}

Note

При перенаправлении на защищённый URL-адрес, если не требуются дополнительные правила перенаправления, рекомендуется использовать промежуточное ПО перенаправления на HTTPS. Дополнительные сведения см. в разделе Обязательное использование HTTPS.

Пример приложения позволяет продемонстрировать использование AddRedirectToHttps или AddRedirectToHttpsPermanent. Добавьте этот метод расширения в RewriteOptions. Выполните небезопасный запрос к приложению по любому URL-адресу. Закройте предостережение системы безопасности о том, что самозаверяющий сертификат не является доверенным, или создайте исключение, чтобы сделать сертификат доверенным.

Исходный запрос с использованием AddRedirectToHttps(301, 5001): http://localhost:5000/secure

Окно браузера, в котором средства разработчика отслеживают запросы и отклики: добавление перенаправления на HTTPS

Исходный запрос с использованием AddRedirectToHttpsPermanent: http://localhost:5000/secure

Окно браузера, в котором средства разработчика отслеживают запросы и отклики: добавление перенаправления на постоянный HTTPS

URL rewrite

Используйте AddRewrite, чтобы создать правило для переопределения URL-адресов. Первый параметр содержит регулярное выражение, соответствующее пути входящего URL-адреса. Второй параметр — строка замены. Третий параметр, skipRemainingRules: {true|false}, указывает промежуточному ПО, следует ли пропустить дополнительные правила перезаписи, если применяется текущее правило.

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

Исходный запрос: /rewrite-rule/1234/5678

Окно браузера со средствами разработчика, отслеживающими запрос и ответ: добавление правила перезаписи

Символ каретки (^) в начале выражения означает, что сопоставление начинается с начала пути URL-адреса.

В предыдущем примере с правилом перенаправления, redirect-rule/(.*), в начале регулярного выражения отсутствует символ каретки (^). Таким образом, для успешного совпадения в пути перед redirect-rule/ могут находиться любые символы.

Path Match
/redirect-rule/1234/5678 Yes
/my-cool-redirect-rule/1234/5678 Yes
/anotherredirect-rule/1234/5678 Yes

Правило переопределения ^rewrite-rule/(\d+)/(\d+) соответствует путям, только если они начинаются с rewrite-rule/. В следующей таблице обратите внимание на разницу в сопоставлении.

Path Match
/rewrite-rule/1234/5678 Yes
/my-cool-rewrite-rule/1234/5678 No
/anotherrewrite-rule/1234/5678 No

После части ^rewrite-rule/ выражения стоят две группы записи (\d+)/(\d+). \d означает соответствие цифре (числу). Знак "плюс" (+) означает соответствие одному или нескольким предшествующим символам. Таким образом, URL должен содержать число, за которым следует наклонная черта, а затем другое число. Эти группы захвата подставляются в перезаписанный URL-адрес как $1 и $2. Строка замены для правила перезаписи подставляет захваченные группы в строку запроса. Запрошенный путь /rewrite-rule/1234/5678 переопределяется, чтобы ресурс можно было получить по адресу /rewritten?var1=1234&var2=5678. Если в исходном запросе присутствует строка запроса, она сохраняется при переопределении URL-адреса.

Для получения ресурса не требуется дополнительный запрос к серверу. Если ресурс существует, он извлекается и возвращается клиенту с кодом состояния 200 (ОК). Так как клиент не перенаправляется, URL-адрес в адресной строке браузера не изменяется. Клиенты не могут узнать, что на сервере произошла операция переопределения URL-адреса.

Note

Используйте skipRemainingRules: true при любой возможности, так как правила сопоставления потребляют много ресурсов и ухудшают время отклика приложения. Чтобы максимально ускорить отклик приложения:

  • Расположите правила перезаписи в порядке от наиболее часто срабатывающего правила к наименее часто срабатывающему.
  • Пропускать обработку оставшихся правил, если найдено совпадение и дальнейшая обработка правил не требуется.

Apache mod_rewrite (модуль для перезаписи URL на веб-сервере Apache)

Для применения правил mod_rewrite Apache можно использовать AddApacheModRewrite. Убедитесь, что файл правил развертывается вместе с приложением. Дополнительные сведения и примеры правил mod_rewrite см. в статье о правилах mod_rewrite Apache.

StreamReader используется для чтения правил из файла 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}"));
}

Пример приложения перенаправляет запросы из /apache-mod-rules-redirect/(.\*) в /redirected?id=$1. Код состояния ответа — 302 - Найден.

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

Исходный запрос: /apache-mod-rules-redirect/1234

Окно браузера с инструментами разработчика, отслеживающими запросы и ответы: добавить перенаправление Apache mod

Промежуточное ПО поддерживает следующие серверные переменные Apache mod_rewrite:

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

Правила модуля переопределения URL-адресов для IIS

Чтобы использовать тот же набор правил, который применяется к модулю переопределения URL-адресов для IIS, используйте AddIISUrlRewrite. Убедитесь, что файл правил развертывается вместе с приложением. Не настраивайте промежуточное ПО на использование файла web.config приложения при работе в IIS Windows Server. В IIS эти правила нужно хранить за пределами файла приложения web.config, чтобы предотвратить конфликты с модулем переопределения для IIS. Дополнительные сведения и примеры правил модуля переопределения URL-адресов для IIS см. в разделах Использование модуля переопределения URL-адресов 2.0 и Справочник по конфигурации модуля переопределения URL-адресов.

Используется StreamReader для чтения правил из 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}"));
}

Пример приложения переопределяет запросы с /iis-rules-rewrite/(.*) на /rewritten?id=$1. Клиенту отправляется отклик с кодом состояния 200 (ОК).

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

Исходный запрос: /iis-rules-rewrite/1234

Окно браузера, в котором средства разработчика отслеживают запрос и ответ: добавление правила перезаписи URL в IIS

Если у вас активен модуль IIS Rewrite с настроенными правилами уровня сервера, которые могут нежелательным образом повлиять на ваше приложение, вы можете отключить модуль IIS Rewrite для конкретного приложения. Дополнительные сведения см. в разделе Отключение модулей IIS.

Неподдерживаемые функции

ПО промежуточного слоя не поддерживает следующие функции в модуле переопределения URL-адресов для служб IIS:

  • Правила для исходящего трафика
  • Пользовательские переменные сервера
  • Wildcards
  • LogRewrittenUrl

Поддерживаемые переменные сервера

ПО промежуточного слоя поддерживает следующие переменные сервера в модуле переопределения URL-адресов для 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

Note

Можно также получить IFileProvider с помощью PhysicalFileProvider. Этот подход может обеспечить большую гибкость в выборе расположения файлов правил перезаписи. Убедитесь, что ваши файлы правил перезаписи развернуты на сервере по пути, который вы укажете.

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

Правило на основе метода

Используйте Add, чтобы реализовать собственную логику правил в методе. Add открывает доступ к RewriteContext, который делает HttpContext доступным для использования в вашем методе. RewriteContext.Result определяет, как осуществляется дополнительная обработка в конвейере. Установите значение одного из полей RuleResult из следующей таблицы.

Результат перезаписи контекста Action
RuleResult.ContinueRules (по умолчанию) Продолжение применения правил.
RuleResult.EndResponse Остановка применения правил и отправка отклика.
RuleResult.SkipRemainingRules Прекратите применять правила и передайте контекст следующему промежуточному обработчику.
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}"));
}

Пример приложения демонстрирует метод, который перенаправляет запросы к путям, оканчивающимся на .xml. Если запрос выполняется для /file.xml, запрос перенаправляется к /xmlfiles/file.xml. Код состояния получает значение 301 - Moved Permanently. Когда браузер отправляет новый запрос для /xmlfiles/file.xml, промежуточное ПО для статических файлов обслуживает файл клиенту из папки wwwroot/xmlfiles. Для перенаправления необходимо явно указать код состояния ответа. В противном случае возвращается код состояния 200 (ОК) и перенаправление на стороне клиента не происходит.

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

Этот подход также переопределяет запросы. В примере приложения показано переопределение пути для любого запроса текстового файла, чтобы отправить текстовый файл file.txt из папки wwwroot. ПО промежуточного слоя статических файлов предоставляет файл по обновленному пути запроса:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

RewriteRules.cs:

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

    if (request.Path.Value.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
    {
        context.Result = RuleResult.SkipRemainingRules;
        request.Path = "/file.txt";
    }
}

Правило на основе IRule

Используйте Add, чтобы использовать собственную логику правил в классе, реализующем интерфейс IRule. IRule позволяет более гибко применять правила, основанные на методах. Класс реализации может включать конструктор, который позволяет передавать параметры для метода 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}"));
}

Значения параметров в примере приложения для extension и newPath проверяются на соответствие нескольким условиям. extension должен содержать одно из значений: .png, .jpg или .gif. Если newPath недопустим, возникает исключение ArgumentException. Если запрос выполняется для image.png, запрос перенаправляется к /png-images/image.png. Если запрос выполняется для image.jpg, запрос перенаправляется к /jpg-images/image.jpg. Для кода состояния устанавливается значение 301 - Moved Permanently, а также задается значение context.Result, чтобы остановить обработку правил и отправить ответ.

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

Исходный запрос: /image.png

Окно браузера, в котором средства разработчика отслеживают запросы и отклики для image.png

Исходный запрос: /image.jpg

Окно браузера, в котором средства разработчика отслеживают запросы и отклики для image.jpg

Примеры регулярных выражений

Goal Пример строки регулярного выражения
Пример сопоставления
Строка замены &
Пример вывода
Переопределение пути в строке запроса ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Удалить завершающий слеш (.*)/$
/path/
$1
/path
Добавление косой черты в конце (.*[^/])$
/path
$1/
/path/
Избегайте переписывания конкретных запросов ^(.*)(?<!\.axd)$ или ^(?!.*\.axd$)(.*)$
Да: /resource.htm
Нет: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Переупорядочение сегментов URL-адреса path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Замена сегмента URL-адреса ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

Этот документ содержит вводные сведения о переопределении URL-адресов и инструкции по использованию ПО промежуточного слоя для переопределения URL-адресов в приложениях ASP.NET Core.

Переопределение URL-адресов представляет собой изменение URL-адресов запросов на основе одного или нескольких предопределенных правил. Переопределение URL-адресов создает абстракцию между расположениями ресурсов и их адресами, позволяя убрать тесную связь между ними. Существует несколько сценариев, где может пригодиться переопределение URL-адресов:

  • Временное или постоянное перемещение или замещение ресурсов сервера с сохранением стабильных указателей для этих ресурсов.
  • Разделение обработки запросов между разными приложениями или разными областями одного приложения.
  • Удаление, добавление или переупорядочение сегментов URL-адресов для входящих запросов.
  • Оптимизация общедоступных URL-адресов в целях оптимизации для поисковых систем (SEO).
  • Разрешение использования понятных общедоступных URL-адресов, чтобы помочь посетителям прогнозировать содержимое, возвращаемое в результате запроса ресурса.
  • Перенаправление небезопасных запросов на защищенные конечные точки.
  • Запрет вставки прямых ссылок, когда внешний сайт использует статический ресурс, размещенный на другом сайте, привязывая ресурс к своему содержимому.

Note

Переопределение URL-адресов может снижать производительность приложения. Следует по возможности ограничить число и сложность правил.

Просмотреть или скачать образец кода (описание загрузки)

Перенаправление и переопределение URL-адресов

Разница между перенаправлением и переопределением URL-адресов может показаться незначительной, но она оказывает существенное влияние на предоставление ресурсов клиентам. ПО промежуточного слоя для переопределения URL-адресов в ASP.NET Core удовлетворяет потребность в обеих этих функциях.

Перенаправление URL-адресов является операцией на стороне клиента, которая предписывает клиенту обратиться к ресурсу по другому адресу, отличному от запрошенного клиентом. Для этого используется круговое обращение к серверу. URL-адрес перенаправления, возвращаемый клиенту, отображается в адресной строке браузера, когда клиент отправляет новый запрос для данного ресурса.

Если /resourceперенаправляется на /different-resource, сервер отвечает, что клиенту следует получить ресурс в /different-resource с кодом состояния, указывающим, что такое перенаправление является временным или постоянным.

Конечная точка службы WebAPI была временно изменена с версии 1 (v1) на версию 2 (v2) на сервере. Клиент делает запрос к службе по пути версии 1 /v1/api. Сервер отправляет ответ 302 (Обнаружено) с новым временным путем для службы версии 2 /v2/api. Клиент делает второй запрос к службе по URL-адресу перенаправления. Сервер отвечает кодом состояния 200 (OK).

При перенаправлении запросов на другой URL-адрес можно указать, является ли оно постоянным или временным, предоставив код состояния в ответе:

  • Код состояния 301 - Moved Permanently используется, когда ресурс имеет новый постоянный URL-адрес и вы хотите сообщить клиенту, что все последующие запросы для этого ресурса должны использовать новый URL-адрес. Клиент может кэшировать и повторно использовать отклик при получении кода состояния 301.

  • Код состояния 302 (найдено) используется, когда перенаправление является временным или может меняться. Код состояния 302 указывает клиенту, что не нужно сохранять URL-адрес и использовать его в будущем.

Дополнительные сведения о кодах состояния см. в статье RFC 9110: определения кода состояния.

Переопределение URL-адреса является операцией на стороне сервера для предоставления ресурса с другого адреса ресурса, отличного от запрошенного клиентом. Переопределение URL-адреса не требует кругового обращения к серверу. Переопределенный URL-адрес не возвращается клиенту и не отображается в адресной строке браузера.

Если /resourceперезаписывается в /different-resource, сервер на внутреннем уровне получает и возвращает ресурс по адресу /different-resource.

Хотя клиент может быть в состоянии получить ресурс по переопределенному URL-адресу, когда клиент отправляет запрос и получает отклик, он не уведомляется о наличии ресурса по переопределенному URL-адресу.

На сервере конечная точка службы WebAPI была изменена с версии 1 (v1) на версию 2 (v2). Клиент делает запрос к службе по пути /v1/api версии 1. URL-адрес запроса переписывается для доступа к службе по пути версии 2 /v2/api. Служба отвечает клиенту кодом состояния 200 (OK).

Пример приложения с переопределением URL-адресов

Вы можете изучить возможности компонента промежуточного ПО для перезаписи URL-адресов с помощью примерного приложения. Это приложение применяет правила перенаправления и переопределения и показывает перенаправленный или переопределенный URL-адрес для нескольких сценариев.

Когда использовать промежуточное ПО для перезаписи URL-адресов

Используйте ПО промежуточного слоя для переопределения URL-адресов, если невозможно использовать следующие подходы:

Кроме того, используйте ПО промежуточного слоя, когда приложение размещается на сервере HTTP.sys (который раньше назывался WebListener).

Основные причины использования технологий перезаписи URL-адресов на стороне сервера в IIS, Apache и Nginx:

  • ПО промежуточного слоя не поддерживает все функции этих модулей.

    Некоторые функции серверных модулей не работают с проектами ASP.NET Core, например ограничения IsFile и IsDirectory для модуля переопределения IIS. В этих случаях следует использовать ПО промежуточного слоя.

  • Производительность ПО промежуточного слоя, скорее всего, не соответствует производительности модулей.

    Тестирование производительности — это единственный способ узнать точно, какой подход больше всего снижает производительность или является ли такое снижение незначительным.

Package

Чтобы включить ПО промежуточного слоя в проект, добавьте ссылки на пакет в метапакет Microsoft.AspNetCore.App в файле проекта, который содержит пакет Microsoft.AspNetCore.Rewrite.

Если метапакет Microsoft.AspNetCore.App не используется, добавьте ссылку на проект в пакет Microsoft.AspNetCore.Rewrite.

Расширение и параметры

Настройте правила перезаписи и перенаправления URL-адресов, создав экземпляр класса RewriteOptions и используя методы расширения для каждого из правил перезаписи. Несколько правил можно объединить в цепочку в том порядке, в котором они должны обрабатываться. RewriteOptions передаются в ПО промежуточного слоя для переопределения URL-адресов по мере его добавления в конвейер запросов с помощью 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}"));
}

Перенаправить адреса без www на www

Три параметра разрешают приложению перенаправлять запросы, отличные от www, на www:

  • AddRedirectToWwwPermanent: Постоянно перенаправлять запрос на поддомен www, если запрос не относится к типу www. Перенаправляет, используя код состояния Status308PermanentRedirect.

  • AddRedirectToWww: Перенаправьте запрос на поддомен www, если входящий запрос не www. Перенаправляет с кодом состояния Status307TemporaryRedirect. Перегрузка позволяет указать код состояния в ответе. Используйте поле класса StatusCodes для назначения кода состояния.

Перенаправление URL-адреса

Используйте AddRedirect для перенаправления запросов. Первый параметр содержит регулярное выражение, соответствующее пути входящего URL-адреса. Второй параметр — строка замены. Третий параметр (при его наличии) указывает код состояния. Если код состояния не задан, по умолчанию используется код 302 (найдено), указывающий, что ресурс временно перемещен или заменен.

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

В браузере с включёнными инструментами разработчика отправьте запрос к тестовому приложению по пути /redirect-rule/1234/5678. Регулярное выражение соответствует пути запроса в redirect-rule/(.*), и этот путь заменяется на /redirected/1234/5678. URL-адрес перенаправления отправляется обратно клиенту с кодом состояния 302 (найдено). Браузер выполняет новый запрос на URL-адрес перенаправления, отображаемый в адресной строке. Поскольку в примере приложения нет правил, соответствующих URL-адресу перенаправления:

  • Второй запрос получает от приложения ответ 200 (ОК).
  • Текст ответа показывает URL-адрес перенаправления.

При перенаправлении URL-адреса используется круговое обращение к серверу.

Warning

Соблюдайте осторожность при задании правил перенаправления. Правила перенаправления проверяются при каждом запросе к приложению, в том числе после перенаправления. Можно легко случайно создать бесконечный цикл перенаправлений.

Исходный запрос: /redirect-rule/1234/5678

Добавление перенаправления. Окно браузера, в котором средства разработчика отслеживают запросы и отклики

Часть выражения, заключенная в скобки, называется группой записи. Точка (.) в выражении означает совпадение с любым символом. Звездочка (*) означает, что предыдущий символ может встречаться ноль или более раз. Таким образом, два последних сегмента пути URL-адреса, 1234/5678, захватываются группой захвата (.*). Любое значение, указанное в URL-адресе запроса после redirect-rule/, перехватывается этой группой записи.

В строке замены захваченные группы подставляются в строку с помощью знака доллара ($), за которым следует порядковый номер группы захвата. Первое значение группы захвата получают с помощью $1, второе — с помощью $2, и далее они идут последовательно для групп захвата в вашем регулярном выражении. В регулярном выражении правила перенаправления в примере приложения есть только одна захватывающая группа, поэтому в строке замены подставляется только одна группа — $1. Когда применяется правило, URL-адрес становится /redirected/1234/5678.

Перенаправление URL-адреса на защищённую конечную точку

Используйте AddRedirectToHttps, чтобы перенаправлять HTTP-запросы на тот же узел и путь с использованием протокола HTTPS. Если код состояния не указан, ПО промежуточного слоя по умолчанию использует значение 302 (найдено). Если порт не указан:

  • По умолчанию используется промежуточное ПО null.
  • Схема меняется на https (протокол HTTPS), и клиент обращается к ресурсу через порт 443.

В следующем примере показано, как задать код 301 - Moved Permanently состояния и изменить порт на 5001.

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

    app.UseRewriter(options);
}

Используйте AddRedirectToHttpsPermanent, чтобы перенаправить небезопасные запросы на тот же узел и путь с использованием безопасного протокола HTTPS через порт 443. ПО промежуточного слоя задает код состояния 301 - Moved Permanently.

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

    app.UseRewriter(options);
}

Note

При перенаправлении на защищённый URL-адрес, если не требуются дополнительные правила перенаправления, рекомендуется использовать промежуточное ПО перенаправления HTTPS. Дополнительные сведения см. в разделе Обязательное использование HTTPS.

Пример приложения позволяет продемонстрировать использование AddRedirectToHttps или AddRedirectToHttpsPermanent. Добавьте этот метод расширения в RewriteOptions. Выполните небезопасный запрос к приложению по любому URL-адресу. Закройте предостережение системы безопасности о том, что самозаверяющий сертификат не является доверенным, или создайте исключение, чтобы сделать сертификат доверенным.

Исходный запрос с использованием AddRedirectToHttps(301, 5001): http://localhost:5000/secure

Добавление перенаправления на HTTPS. Окно браузера, в котором средства разработчика отслеживают запросы и отклики

Исходный запрос с использованием AddRedirectToHttpsPermanent: http://localhost:5000/secure

Добавление перенаправления на постоянный HTTPS. Окно браузера, в котором средства разработчика отслеживают запросы и отклики

URL rewrite

Используйте AddRewrite, чтобы создать правило для переопределения URL-адресов. Первый параметр содержит регулярное выражение, соответствующее пути входящего URL-адреса. Второй параметр — строка замены. Третий параметр skipRemainingRules: {true|false}, указывает промежуточному ПО, следует ли пропускать дополнительные правила перезаписи, если текущее правило применяется.

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

Исходный запрос: /rewrite-rule/1234/5678

Добавить переопределение: окно браузера, в котором инструменты разработчика отслеживают запрос и ответ

Символ каретки (^) в начале выражения означает, что сопоставление начинается с начала пути URL.

В предыдущем примере с правилом перенаправления redirect-rule/(.*) в начале регулярного выражения нет символа каретки (^). Таким образом, для успешного совпадения в пути перед redirect-rule/ могут находиться любые символы.

Path Match
/redirect-rule/1234/5678 Yes
/my-cool-redirect-rule/1234/5678 Yes
/anotherredirect-rule/1234/5678 Yes

Правило переопределения ^rewrite-rule/(\d+)/(\d+) соответствует путям, только если они начинаются с rewrite-rule/. В следующей таблице обратите внимание на разницу в сопоставлении.

Path Match
/rewrite-rule/1234/5678 Yes
/my-cool-rewrite-rule/1234/5678 No
/anotherrewrite-rule/1234/5678 No

После части выражения ^rewrite-rule/ следуют две группы захвата (\d+)/(\d+). \d означает соответствует цифре (числу). Знак "плюс" (+) означает соответствие одному или нескольким предшествующим символам. Таким образом, URL должен содержать число, за которым следует символ /, а затем другое число. Эти группы захвата подставляются в перезаписанный URL-адрес как $1 и $2. Строка замены для правила перезаписи подставляет захваченные группы в строку запроса. Запрошенный путь /rewrite-rule/1234/5678 переопределяется, чтобы ресурс можно было получить по адресу /rewritten?var1=1234&var2=5678. Если в исходном запросе присутствует строка запроса, она сохраняется при переопределении URL-адреса.

Для получения ресурса не требуется отправлять запрос на сервер и получать от него ответ. Если ресурс существует, он извлекается и возвращается клиенту с кодом состояния 200 (ОК). Так как клиент не перенаправляется, URL-адрес в адресной строке браузера не изменяется. Клиенты не могут узнать, что на сервере произошла операция переопределения URL-адреса.

Note

Используйте skipRemainingRules: true при любой возможности, так как правила сопоставления потребляют много ресурсов и ухудшают время отклика приложения. Чтобы максимально ускорить отклик приложения:

  • Расположите правила перезаписи в порядке от наиболее часто срабатывающего правила к наименее часто срабатывающему.
  • Пропускать обработку оставшихся правил при совпадении, если не требуется дальнейшая обработка правил.

Apache mod_rewrite (модуль для перезаписи URL на веб-сервере Apache)

Для применения правил mod_rewrite Apache можно использовать AddApacheModRewrite. Убедитесь, что файл правил развертывается вместе с приложением. Дополнительные сведения и примеры правил mod_rewrite см. в статье о правилах mod_rewrite Apache.

StreamReader используется для чтения правил из файла 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}"));
}

Пример приложения перенаправляет запросы из /apache-mod-rules-redirect/(.\*) в /redirected?id=$1. Код состояния ответа — 302 — Найдено.

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

Исходный запрос: /apache-mod-rules-redirect/1234

Добавить перенаправление Apache mod: окно браузера с открытыми инструментами разработчика, отслеживающими запросы и ответы

Промежуточное ПО поддерживает следующие серверные переменные Apache mod_rewrite:

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

Правила модуля переопределения URL-адресов для IIS

Чтобы использовать тот же набор правил, который применяется к модулю переопределения URL-адресов для IIS, используйте AddIISUrlRewrite. Убедитесь, что файл правил развертывается вместе с приложением. Не настраивайте промежуточное ПО на использование файла web.config приложения при работе в IIS на Windows Server. В IIS эти правила нужно хранить за пределами файла приложения web.config, чтобы предотвратить конфликты с модулем переопределения для IIS. Дополнительные сведения и примеры правил модуля переопределения URL-адресов для IIS см. в разделах Использование модуля переопределения URL-адресов 2.0 и Справочник по конфигурации модуля переопределения URL-адресов.

Используется StreamReader для чтения правил из 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}"));
}

Пример приложения переопределяет запросы с /iis-rules-rewrite/(.*) на /rewritten?id=$1. Клиенту отправляется отклик с кодом состояния 200 (ОК).

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

Исходный запрос: /iis-rules-rewrite/1234

Добавление правила перезаписи URL-адресов в IIS: окно браузера со средствами разработчика, отслеживающими запрос и ответ

Если у вас активен модуль IIS Rewrite и в нём настроены правила уровня сервера, которые могут нежелательным образом повлиять на ваше приложение, вы можете отключить модуль IIS Rewrite для этого приложения. Дополнительные сведения см. в разделе Отключение модулей IIS.

Неподдерживаемые функции

ПО промежуточного слоя, выпущенное вместе с ASP.NET Core 2.x, не поддерживает следующие функции в модуле переопределения URL-адресов для IIS:

  • Правила для исходящего трафика
  • Пользовательские переменные сервера
  • Wildcards
  • LogRewrittenUrl

Поддерживаемые переменные сервера

ПО промежуточного слоя поддерживает следующие переменные сервера в модуле переопределения URL-адресов для 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

Note

Можно также получить IFileProvider через PhysicalFileProvider. Такой подход может обеспечить бо́льшую гибкость в выборе расположения файлов правил перезаписи. Убедитесь, что файлы правил перезаписи развернуты на сервере по указанному вами пути.

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

Правило на основе метода

Используйте Add, чтобы реализовать собственную логику правил в методе. Add открывает доступ к RewriteContext, который предоставляет HttpContext для использования в вашем методе. RewriteContext.Result определяет, как осуществляется дополнительная обработка в конвейере. Установите значение одного из полей RuleResult из следующей таблицы.

Результат перезаписи контекста Action
RuleResult.ContinueRules (по умолчанию) Продолжение применения правил.
RuleResult.EndResponse Остановка применения правил и отправка отклика.
RuleResult.SkipRemainingRules Прекратите применять правила и передайте контекст следующему промежуточному обработчику.
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}"));
}

Приложение-пример демонстрирует способ, который перенаправляет запросы к путям, которые заканчиваются на .xml. Если запрос выполняется для /file.xml, запрос перенаправляется к /xmlfiles/file.xml. Код состояния получает значение 301 - Moved Permanently. Когда браузер отправляет новый запрос для /xmlfiles/file.xml, промежуточное ПО для статических файлов обслуживает файл клиенту из папки wwwroot/xmlfiles. Для перенаправления необходимо явно указать код состояния ответа. В противном случае возвращается код состояния 200 (ОК) и перенаправление на стороне клиента не происходит.

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

Этот подход также переопределяет запросы. В примере приложения показано переопределение пути для любого запроса текстового файла, чтобы отправить текстовый файл file.txt из папки wwwroot. ПО промежуточного слоя статических файлов предоставляет файл по обновленному пути запроса:

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

        app.UseRewriter(options);
    }

    app.UseStaticFiles();

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

RewriteRules.cs:

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

    if (request.Path.Value.EndsWith(".txt", StringComparison.OrdinalIgnoreCase))
    {
        context.Result = RuleResult.SkipRemainingRules;
        request.Path = "/file.txt";
    }
}

Правило на основе IRule

Используйте Add, чтобы использовать собственную логику правил в классе, реализующем интерфейс IRule. IRule позволяет более гибко применять правила, основанные на методах. Класс реализации может включать конструктор, который позволяет передавать параметры для метода 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}"));
}

Значения параметров в примере приложения для extension и newPath проверяются на соответствие нескольким условиям. extension должен содержать одно из значений: .png, .jpg или .gif. Если newPath недопустим, вызывается исключение ArgumentException. Если запрос выполняется для image.png, запрос перенаправляется к /png-images/image.png. Если запрос выполняется для image.jpg, запрос перенаправляется к /jpg-images/image.jpg. Для кода состояния устанавливается значение 301 - Moved Permanently, а также задается значение context.Result, чтобы остановить обработку правил и отправить ответ.

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

Исходный запрос: /image.png

Для файла image.png: окно браузера с инструментами разработчика, отслеживающими запросы и ответы

Исходный запрос: /image.jpg

Для файла image.jpg: окно браузера со средствами разработчика для отслеживания запросов и ответов

Примеры регулярных выражений

Goal Пример строки регулярного выражения
Пример сопоставления
Строка замены &
Пример вывода
Переопределение пути в строке запроса ^path/(.*)/(.*)
/path/abc/123
path?var1=$1&var2=$2
/path?var1=abc&var2=123
Удалить завершающий слеш (.*)/$
/path/
$1
/path
Добавление косой черты в конце (.*[^/])$
/path
$1/
/path/
Избегайте переписывания конкретных запросов ^(.*)(?<!\.axd)$ или ^(?!.*\.axd$)(.*)$
Да: /resource.htm
Нет: /resource.axd
rewritten/$1
/rewritten/resource.htm
/resource.axd
Переупорядочение сегментов URL-адреса path/(.*)/(.*)/(.*)
path/1/2/3
path/$3/$2/$1
path/3/2/1
Замена сегмента URL-адреса ^(.*)/segment2/(.*)
/segment1/segment2/segment3
$1/replaced/$2
/segment1/replaced/segment3

Дополнительные ресурсы