URL Rewriting

Введение в URL Rewriting

Последнее обновление: 03.11.2022

Функциональность URL Rewriting позволяет контролировать доступ к определенным URL-адресам в приложении. В частности, мы можем выполнить переопределение адресов, которые используются для доступа к ресурсам приложения. Например, URL Rewriting позволяет решить такие стандартные проблемы, как перенаправление с домена с www на домен без www и наоборот или перенаправление с протокола http на https.

URL Rewriting реализуется до того, как запрос попадет в систему маршрутизации, и начнется его непосредственное выполнение в конвейере MVC. Запрошенный адрес изначально может отсутствовать в приложении, однако URL Rewriting может изменить этот адрес на любой приемлемый.

Для подключения компонента URL Rewriting используется метод расширения UseRewriter(), который в качестве параметра принимает объект RewriteOptions, задающий все правила переопределения адресов URL:

using Microsoft.AspNetCore.Rewrite; // Пакет с middleware URL Rewriting

var builder = WebApplication.CreateBuilder();

var app = builder.Build();

// подключаем URL Rewriting
var options = new RewriteOptions();
app.UseRewriter(options);

app.MapGet("/home", async context => await context.Response.WriteAsync("Hello World!"));

app.Run();

Правда, в данном случае для RouteOptions пока еще не определено никаких правил переопределения URL, которые мы можем задать с помощью специальных методов:

  • AddRedirect(): выполняет переадресацию с отправкой статусного кода HTTP 301

  • AddRewrite(): подменяет один адрес другим

  • AddRedirectToWww(): выполняет переадресацию на поддомен WWW

  • AddRedirectToWwwPermanent(): выполняет переадресацию на поддомен WWW с отправкой статусного кода HTTP 301 (постоянная переадресация)

  • AddRedirectToNonWww(): выполняет переадресацию с поддомена WWW на основной домен

  • AddRedirectToNonWwwPermanent(): выполняет переадресацию с поддомена WWW на основной домен с отправкой статусного кода HTTP 301 (постоянная переадресация)

  • AddRedirectToHttps(): выполняет переадресацию на протокол HTTPS

  • AddRedirectToHttpsPermanent(): выполняет переадресацию на протокол HTTPS с отправкой статусного кода HTTP 301 (постоянная переадресация)

  • AddIISUrlRewrite(): в качестве источника правил для переопределения URL использует правила для IIS

  • AddApacheModRewrite(): в качестве источника правил для переопределения URL использует правила для Apache

AddRedirect

Метод AddRedirect() реализован как метод расширения для типа RewriteOptions и имеет две формы:

public static RewriteOptions AddRedirect (this RewriteOptions options, string regex, string replacement);
public static RewriteOptions AddRedirect (this RewriteOptions options, string regex, string replacement, int statusCode);
  • В качестве параметра regex метод принимает регулярное выражение, которому должен соответствовать входящий адрес URL. В качестве адреса в метод AddRedirect передается та часть URL, которая образуется с помощью объединения значений Request.Path и Request.QueryString. То есть, если полный запрошенный адрес http://localhost:1234/home/index?id=4, то в метод AddRedirect передается home/index?id=4

  • Параметр replacement представляет выражение, которое указывает, по какому адресу нужно выполнять переадресацию.

  • Параметр statusCode устанавливает отправляемый статусный код.

Например, нам надо, чтобы с адресов с конечным слешем (например, localhost/home/) шло перенаправление на тот же адрес только без слеша (например, localhost/home):

using Microsoft.AspNetCore.Rewrite; // Пакет с middleware URL Rewriting

var builder = WebApplication.CreateBuilder();

var app = builder.Build();

// подключаем URL Rewriting
var options = new RewriteOptions().AddRedirect("(.*)/$", "$1");
app.UseRewriter(options);

app.MapGet("/home", async context => await context.Response.WriteAsync("Hello World!"));

app.Run();

Регулярное выражение "(.*)/$" указывает на любой адрес, который завершается слешем. Второй параметр указывает, что в качестве адреса для перенаправления будет использоваться та часть исходного URL, которая идет до слеша: (.*). То есть "$1" указывает на первую группу в регулярном выражении "(.*)/$".

То есть в данном случае удаляется концевой слеш (например, перенаправляется с "localhost:1234/home/" на "localhost:1234/home").

Рассмотрим другую ситуацию. Например, мы хотим перенаправлять с адреса home/ на home/index:

using Microsoft.AspNetCore.Rewrite; // Пакет с middleware URL Rewriting

var builder = WebApplication.CreateBuilder();

var app = builder.Build();

// подключаем URL Rewriting
var options = new RewriteOptions()
					.AddRedirect("home[/]?$", "home/index"); // переадресация с home на home/index
app.UseRewriter(options);

app.MapGet("/", async context => await context.Response.WriteAsync("Hello World!"));
app.MapGet("/home", async context => await context.Response.WriteAsync("Home Page!"));
app.MapGet("/home/index", async context => await context.Response.WriteAsync("Home Index Page!"));

app.Run();

Для примера с помощью метода app.MapGet заданы тестовые маршруты, в итоге при обращении по адресу "home" произойдет переадресация на адрес "home/index", и мы увидим в браузере строку "Home Index Page!".

При этом можно задать последовательно сразу несколько правил:

var options = new RewriteOptions()
                .AddRedirect("home[/]?$", "home/index") // переадресация с home на home/index
                .AddRedirect("(.*)/$", "$1");           // удаление концевого слеша

AddRewrite

Метод AddRewrite() подменяет входящий адрес другим. Первый параметр метода указывает на регулярное выражение, которому должен соответствовать адрес. Второй параметр указывает, на какой адрес надо подменить входящий. Третий параметр - булевое значение устанавливает, надо ли прекратить применение остальных правил, если адрес соответствует выражению из первого параметра. Например:

using Microsoft.AspNetCore.Rewrite; // Пакет с middleware URL Rewriting

var builder = WebApplication.CreateBuilder();

var app = builder.Build();

// подключаем URL Rewriting
var options = new RewriteOptions()
            .AddRedirect("(.*)/$", "$1")
            .AddRewrite("home/index", "home/about", skipRemainingRules: false);
app.UseRewriter(options);

app.MapGet("/", async context => await context.Response.WriteAsync("Hello World!"));
app.MapGet("/home/about", async context =>
        await context.Response.WriteAsync($"About: {context.Request.Path}"));
app.MapGet("/home/index", async context =>
        await context.Response.WriteAsync("Home Index Page!"));

app.Run();

Правило

AddRewrite("home/index", "home/about", skipRemainingRules: false);

указывает, что при запросе "home/index" в реальности запрос будет сопоставляться с маршрутом "home/about"

URL Rewriting и AddRewrite в ASP.NET Core и C#

При этом переадресации как таковой нет, статусный код 301/302 не отправляется клиенту.

Регистрозависимость

Стоит отметить, что по умолчанию шаблоны в методах Addredirect/AddRewrite регистрозависимы. Что это значит? Возьмем в предыдущем примере следующее правило:

AddRewrite("home/index", "home/about", skipRemainingRules: false);

При запросе "home/index" запрос будет сопоставляться с маршрутом "home/about", однако запрос "Home/Index" по прежнему будет сопоставляться с запросом "home/index".

UrlRewriting и переадресация в ASP.NET Core и C#

Но мы можем выйти из данной ситуации, предваряя шаблон элементом (?i):

var options = new RewriteOptions()
            .AddRedirect("(.*)/$", "$1")
            //шаблон регистронезависимый
            .AddRewrite("(?i)home/index", "home/about", skipRemainingRules: false);

Элементы регулярных выражений в URL Rewriting

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

Например, в рассмотренном выше примере с удалением концевого слеша применялась одна группа:

"(.*)/$"

то есть знак точки "." означает любой символ, знак звездочки "*" означает, что таких символов может быть произвольное количество. И все это объединяется в одну группу - "(.*)". Таким образом, в данном случае группой будет все символы, которые идут до конечного слеша.

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

Для понимания работы групп при рерайтинге/редиректе рассмотрим несколько примеров:

var options = new RewriteOptions()
    .AddRedirect("(.*)/$", "$1")
    .AddRewrite(@"home/index/(\d+)", "home/about?id=$1", skipRemainingRules: false);

В данном случае если адрес соответствует выражению "home/index/(\d+)" (например, "home/index/3"), то фактически происходит обращение по адресу "home/about?id=$1" - $1 здесь также указывает на первую группу в регулярном выражении - (\d+).

Другой пример. Определим следующее правило url rewriting:

using Microsoft.AspNetCore.Rewrite; // Пакет с middleware URL Rewriting

var builder = WebApplication.CreateBuilder();

var app = builder.Build();

// подключаем URL Rewriting
var options = new RewriteOptions()
            .AddRewrite(@"product/(\w+)/(\d+)", 
                "home/products?cat=$1&id=$2",
                skipRemainingRules: false);
app.UseRewriter(options);

app.MapGet("/", async context =>
{
    await context.Response.WriteAsync("Hello World!");
});
app.MapGet("/home/products", async context =>
{
    await context.Response.WriteAsync($"cat: {context.Request.Query["cat"]} id: {context.Request.Query["id"]}");
});
app.Run();

В данном случае используется следующее правило:

AddRewrite(@"product/(\w+)/(\d+)", "home/products?cat=$1&id=$2", 
							skipRemainingRules: false);

Это правило будет транслировать любой запрос типа "product/tablet/23" в запрос типа "home/products/cat=tablet?id=23". То есть теперь у нас две группы: (\w+) и (\d+). Соответственно мы к ним можем обратиться через $1 и $2.

Переопределение адресов приложения и URL-rewriting в ASP.NET Core и C#

В заключении стоит отметить, что использование url rewriting увеличивает накладные расходы на обработку запроса. Поэтому стоит по возможности избегать сложных комплексных правил переопределения строки запроса.

Кроме того, Rewriting Middleware не покрывает всех возможностей нативных модулей в IIS, Apache, Nginx, которые обеспечивают URL-rewriting. Также, нативные модули выше упомянутых веб-серверов демонстрируют большую производительность.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850