Правила IIS для URL Rewriting

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7

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

В более ранних технологиях на платформе ASP.NET (например, в ASP.NET MVC 5) правила для URL Rewriting задавались в основном для IIS с помощью файла конфигурации web.config. И в ASP.NET Core мы также можем использовать все эти правила с помощью специального метода AddIISUrlRewrite().

Итак, добавим в корень проекта новый xml-файл urlrewrite.xml:

<rewrite>
  <rules>
    <rule name="Redirect from home to home/index">
      <match url = "^home$"/>
      <conditions>
          <add input="{REQUEST_URI}" pattern="home" />
      </conditions>
      <action type="Redirect" url ="home/index" />
    </rule>
  </rules>
</rewrite>

Здесь определено одно правило, которое выполняет переадресацию с адреса "/home" на адрес "/home/index". Теперь применим это правило в классе Startup:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Rewrite;
using Microsoft.Extensions.Hosting;

namespace UrlRewritingApp
{
    public class Startup
    {
        public void Configure(IApplicationBuilder app, IHostEnvironment env)
        {
            app.UseDeveloperExceptionPage();

            var options = new RewriteOptions()
                .AddIISUrlRewrite(env.ContentRootFileProvider, "urlrewrite.xml");
            app.UseRewriter(options);

            app.UseRouting();

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

Начиная с версии ASP.NET Core 2.0, можно также загружать файл конфигурации следующим образом:

using System.IO;


using (StreamReader iisReader = File.OpenText("urlrewrite.xml"))
{
	var options = new RewriteOptions().AddIISUrlRewrite(iisReader);
	app.UseRewriter(options);
}

Все правила определяются в элементе <rules>. Каждое правило, представленное элементом <rule>, состоит из трех частей:

  • Pattern – выражение, которому должна соответствовать строка запроса и которое задается в элементе <match>

  • Conditions – различные дополнительные условия, которым должен соответствовать URL-адрес. Например, значения HTTP-заголовков, пути к файлам и т.д.

  • Action – действие, которое должно выполняться, если строка URL соответствует регулярному выражению в Pattern и условиям Conditions

Мы можем использовать несколько правил одновременно, но их выполнение не всегда обязательно. Поэтому у каждого элемента rule определен атрибут StopProcessing. Если имеет значение true, то после выполнения действия в элементе <action> адрес URL, создаваемый данным правилом, передается в конвейер обработки запроса, а другие правила не будут обрабатываться.

Переопределение URL имеет следующий порядок действий:

  1. Строка запроса сравнивается с выражением в элементе match. Если обнаружится, что запрошенный адрес не соответствует выражению, то модуль URL Rewrite Module прекращает обрабатывать текущее правило и переходит к следующему (если задано несколько правил)

  2. Если строка запроса соответствует выражению в элементе match и при этом не задано никаких дополнительных условий с помощью элемента <conditions>, то URL Rewrite Module выполняет действие, которое определено в правиле с помощью элемента <action>.

  3. Если строка запроса соответствует выражению в элементе match и также определены дополнительные условия, то URL Rewrite Module проверяет эти условия. И если URL соответствует этим условиям, то выполняется действие action

Определение условий

Условия, задаваемые элементом <conditions>, определяют дополнительную логику оценки URL на соответствие правилу. Каждое отдельное условие задается с помощью элемента <add > и настраивается с помощью следующих атрибутов:

  • input: определяет объект, который будет использоваться условием для оценки. В частности, в примере выше используется input="{REQUEST_URI}", где "REQUEST_URI" представляет переменную сервера, хранящую запрошенный адрес url. Тут также могут использоваться и другие переменные сервера.

  • pattern: определяет регулярное выражение, которому должен соответствовать объект

  • matchType: принимает следующие значения:

    • Pattern: в этом случае объект (в данном случае адрес URL) сопоставляется с выражением в атрибуте pattern. При других значениях атрибут pattern не учитывается

    • IsFile: определяет, является ли объект (адрес URL) файлом в файловой системе

    • IsDirectory: определяет, является ли объект (адрес URL) каталогом в файловой системе

  • ignoreCase: указывает, надо ли игнорировать регистр адреса URL. По умолчанию равно true, поэтому регистр не учитывается

  • negate: если равно true, то правило применяется, если условие НЕ учитывается. По умолчанию равно false

Определение действий

Если выражение и условия, определяемые правилом, соответствуют объекту (например, адресу URL), то выполняется определенное действие, заданное элементом <action>. Действия могут быть нескольких типов. Тип задается с помощью атрибута type, который принимает следующие значения:

  • Rewrite: заменяет текущую строку запроса URL другой строкой

  • Redirect: выполняет редирект, посылая клиенту статусный код 3хх.

  • CustomResponse: отправляет клиенту определенный статусный код, а также может отправлять специфическое сообщение

  • AbortRequest: сбрасывает подключение для текущего клиента

Другие атрибуты элемента action:

  • url: строка, которая будет заменять текущую строку запроса URL

  • appendQueryString: определяет, должна ли сохраняться та часть строки запроса, которая идет после названия домена и порта. По умолчанию имеет значение true, что значит, что строка запроса со всеми параметрами за исключением названия домена будет сохраняться.

  • redirectType: статусный код переадресации при использовании типа Redirect (301 – Permanent, 302 – Found, 303 – See other, 307 – Temporary)

  • statusCode: определяет статусный код в качестве ответа клиенту при использовании типа CustomResponse

  • subStatusCode: определяет вспомогательный статусный код при использовании типа CustomResponse

  • statusReason: определяет сообщение, отправляемое клиенту вместе со статусным кодом при использовании типа CustomResponse

  • statusDescription: определяет сообщение, отправляемое клиенту в теле ответа при использовании типа CustomResponse

Использование переменных сервера

При изменении URL мы можем использовать следующие переменные сервера:

  • QUERY_STRING: параметры запроса

  • HTTP_HOST: домен

  • SERVER_PORT: номер порта

  • SERVER_PORT_SECURE и HTTPS: указывают, использует ли клиент защищенное подключение

  • REQUEST_URI: полная строка запроса

URL представляется в следующем виде: http(s)://<host>:<port>/<path>?<querystring>. Допустим, пользователь обращается к URL http://www.somesite.com/home/index?id=2&name=3. Тогда IIS сегментирует ее следующим образом:

  • path: представляет сегмент home/index. Эта часть затем сравнивается правилом с выражением, определенным в элементе <match>

  • QUERY_STRING: в данном случае сегмент параметров id=2&name=3

  • HTTP_HOST: сегмент www.somesite.com

  • SERVER_PORT: если номер порта не указан, то по умолчанию равен 80.

  • SERVER_PORT_SECURE равен 0, а HTTPS содержит OFF

  • REQUEST_URI: сегмент home/index?id=2&name=3

При создании условий для правил мы можем ссылаться на эти переменные через выражение вида "{НАЗВАНИЕ_ПЕРЕМЕННОЙ}". Например, нам нужно условие, согласно которому в строке параметров должен быть числовой параметр id:

<add input="{QUERY_STRING}" pattern="id=([0-9]+)" />

Кроме того, нам доступны заголовки HTTP-запроса, например, строку юзер-агента мы можем получить с помощью выражения "{HTTP_USER_AGENT}".

При использовании заголовков запроса надо учитывать, что все дефисы в названии заголовков (например, User-Agent) заменяются символами подчеркивания. Все строчные буквы заменяются заглавными, а к названию переменных добавляется префикс "HTTP_". Как например, из заголовка User-Agent создается переменная HTTP_USER_AGENT.

Обратные ссылки

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

<rewrite>
  <rules>
    <rule name="Redirect">
      <match url = "(.*)"/>
      <conditions>
        <add input="{REQUEST_URI}" pattern="([a-z]+)/([a-z]+)/([0-9]+)" matchType="Pattern" />
      </conditions>
      <action type="Redirect" url ="{C:1}/{C:3}" />
    </rule>
  </rules>
</rewrite>

Все обратные ссылки представляют выражения типа {C:N}, где N - число от 0 до 9. При этом значение {C:0} представляет всю попадающую под условие строку.

То есть из строки запроса "home/index/2" генерировались бы три обратных ссылки C:1 = "home", C:2 = "index" и C:3 = "2". И в соответствии с элементом action шла бы переадресация на адрес "home/2" (то есть "{C:1}/{C:3}").

Кроме условий для создания обратных ссылок могут применяться выражения в элементе match. Все обратные ссылки из выражения match доступны через выражения типа {R:N}, где N - число от 0 до 9. При этом значение {R:0} представляет всю попадающую под условие строку.

Так, рассмотрим другой пример. Допустим, у нас есть правило:

<rule name="Rewrite query" stopProcessing="true">
    <match url="^home/products/([0-9]+)/([_0-9a-z-]+)" />
    <action type="Rewrite" url="home/products?id={R:1}&amp;name={R:2}"  />
</rule>

Например, при запросе http://localhost:50645/Home/Products/2/phones мы получим следующие сегменты:

{R:0} = "Home/Products/2/phones"

{R:1} = "2"

{R:2} = "phones"

В итоге будет формироваться следующая строка URL: http://localhost:50645/Home/Products?id=2&name=phones

Для тестирования мы можем определить следующий метод Configure в классе Startup:

public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
	app.UseDeveloperExceptionPage();

	var options = new RewriteOptions()
			.AddIISUrlRewrite(env.ContentRootFileProvider, "urlrewrite.xml");
	app.UseRewriter(options);

	app.UseRouting();

	app.UseEndpoints(endpoints =>
	{
		endpoints.MapGet("/", async context =>
		{
			await context.Response.WriteAsync("Hello World!");
		});
		endpoints.MapGet("/home/products", async context =>
		{
			await context.Response.WriteAsync($"Values:  id = {context.Request.Query["id"]} " +
					$"name = {context.Request.Query["name"]}");
		});
	});
}
IIS URL Rewriting в ASP.NET Core MVC

Еще один пример - переадресация с домена без www на субдомен www:

<rule name="Redirect to WWW" enabled="true" stopProcessing="true">
    <match url=".*" />
    <conditions logicalGrouping="MatchAll">
        <add input="{HTTP_HOST}" pattern=".*" />
    </conditions>
    <action type="Redirect" url="http://www.localhost:50645/{R:0}" />
</rule>

Или обратное действие - перенаправление с www на домен без www (для домена localhost):

<rule name="Redirect to NonWWW" stopProcessing="true">
    <match url=".*" />
    <conditions logicalGrouping="MatchAll">
	      <add input="{HTTP_HOST}" pattern="^localhost" negate="true" />
    </conditions>
    <action type="Redirect" url="http://localhost:50645/{R:0}" />
</rule>
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850