Создание правил URL Rewriting

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

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

Если необходимо использовать какую-то более сложную логику по переопределению строки запроса, то в этом случае мы можем определить свои правила с помощью методов или целых классов.

Например, пусть ранее сайт использовал технологию php, но затем мигрировал на asp.net, а все документы php были сконвертированы в документы html. То есть ранее сайт, к примеру, использовал адрес http://localhost:1234/some.php, то теперь документ перемещен по адресу http://localhost:1234/html/some.html. Расмотрим на примере создания своих правил, как мы можем решить проблему адресов.

Пусть нужные документы находятся в проекте в папке webroot/html:

Миграция с PHP на ASP.NET Core

Допустим, там находится следующая страница some.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <h2>Hello World!</h2>
</body>
</html>

Вначале рассмотрим простой рерайт без переадресации и определим правило в виде отдельного метода. Для этого изменим класс Startup следующим образом:

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

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

            var options = new RewriteOptions()
                .Add(RewritePHPRequests);

            app.UseRewriter(options);
            app.UseStaticFiles();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }
        static void RewritePHPRequests(RewriteContext context)
        {
            var path = context.HttpContext.Request.Path;
            var pathValue = path.Value; // запрошенный путь
            // если запрос к папке html, возвращаем ошибку 404
            if (path.StartsWithSegments(new PathString("/html")))
            {
                context.HttpContext.Response.StatusCode = StatusCodes.Status404NotFound;
                context.Result = RuleResult.EndResponse;
                return;
            }
            // если запрос к файлам с расширением php, переопределяем запрос на папку html
            if (pathValue.EndsWith(".php", StringComparison.OrdinalIgnoreCase))
            {
                // отрезаем расширение "php" в запрошенном пути и добавляем "html"
                string proccedPath = "/html" + pathValue.Substring(0, pathValue.Length - 3) + "html";
                context.HttpContext.Request.Path = new PathString(proccedPath);
            }
        }
    }
}

Для применения правила у объекта RewriteOptions вызывается метод Add, в который передается делегат Action<RewriteContext>. В данном случае передаем ссылку на метод RewritePHPRequests.

В методе RewritePHPRequests вначале получаем объекты запроса, ответа и запрошенный путь. Если запрошенный путь уже содержит gпуть к каталогу html, то отклоняем его, устанавливая в качестве кода ответа статусный код 404. Для завершения выполнения задается значение context.Result = RuleResult.EndResponse. Тем самым мы предотвращаем прямой доступ к папке html (допустим, необходимо скрыть путь к документам html).

Если запрошенный адрес заканчивается на ".php", то выпоняем ряд преобразований, получая путь к html-документу в папке webroot/html. И затем устанавливаем новое значение у свойства request.Path. Из него последующие компоненты middleware будут брать информацию о запрошенном пути и обработать его соответствующим образом.

Запустим приложение на выполнение и обратимся по адресу http://localhost:xxxx/some.php:

Изменение php на asp.net core

В этом случае произойдет обращение к документу webroot/html/some.html.

Рассмотрим другой способ. Допустим, нам надо не просто переопределить адрес внутри приложения, а выполнить постоянную переадресацию, уведомляя браузеры пользователей и поисковики, что адрес документа окончательно изменился. Для этого определим новый класс RedirectPHPRequests (хотя можно было бы и в виде метода определить):

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Rewrite;
using Microsoft.Net.Http.Headers;
using System;
using System.Text.RegularExpressions;

namespace UrlRewritingApp
{
    public class RedirectPHPRequests : IRule
    {
        private readonly string _extension;
        private readonly PathString _newPath;

        public RedirectPHPRequests(string extension, string newPath)
        {
            if (string.IsNullOrEmpty(extension))
            {
                throw new ArgumentException(nameof(extension));
            }
            if (!Regex.IsMatch(newPath, @"(/[A-Za-z0-9]+)+?"))
            {
                throw new ArgumentException("Запрошенный путь недействителен", nameof(newPath));
            }

            _extension = extension;
            _newPath = new PathString(newPath);
        }

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

            if (request.Path.StartsWithSegments(new PathString(_newPath)))
            {
                return;
            }

            if (request.Path.Value.EndsWith(".php", StringComparison.OrdinalIgnoreCase))
            {
                var response = context.HttpContext.Response;
                var pathValue = request.Path.Value; // запрошенный путь
                response.StatusCode = StatusCodes.Status301MovedPermanently;
                context.Result = RuleResult.EndResponse;
                response.Headers[HeaderNames.Location] = _newPath + pathValue.Substring(0, pathValue.Length - 3) + _extension;
            }
        }
    }
}

Класс правила должен реализовать интерфейс IRule, который определяет метод ApplyRule.

В конструкторе получаем расширение, которое стоит использовать вместо php, а также путь к документам в рамках проекта.

В методе ApplyRule если вдруг запрошенный адрес начинается с названия каталог, где лежать файлы html, то завершаем выполнение. Так как нет смысла выполнять переадресацию, ведь запрос уже идет к файлам в нужном каталоге. Иначе, если запрошен документ php, извлекаем имя документа и формируем новый путь. Этот путь передается через заголовок "Location". И кроме того, устанавливается статусный код постоянной переадресации 301.

Применим этот класс в классе Startup:

public void Configure(IApplicationBuilder app)
{
	app.UseDeveloperExceptionPage();

	var options = new RewriteOptions()
			.Add(new RedirectPHPRequests(extension:"html", newPath:"/html"));

	app.UseRewriter(options);
    app.UseStaticFiles();

	app.UseRouting();

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

Перегруженная версия метода Add класса RewriteOptions принимает объект IRule, в качестве которого в данном случае передается объект RedirectPHPRequests,

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