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

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

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

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

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

Миграция с PHP на ASP.NET Core и C# и создание своих правил URL Rewriting

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

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

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

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

var builder = WebApplication.CreateBuilder();

var app = builder.Build();

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

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

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

app.Run();

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!=null && 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 System.Text.RegularExpressions;
using Microsoft.AspNetCore.Rewrite;
using Microsoft.Net.Http.Headers;

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;
            var pathValue = request.Path.Value; // запрошенный путь

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

            if (pathValue != null && pathValue.EndsWith(".php", StringComparison.OrdinalIgnoreCase))
            {
                var response = context.HttpContext.Response;
                
                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.

Применим этот класс в файле Program.cs:

using UrlRewritingApp;  // пространство имен класса RedirectPHPRequests
using Microsoft.AspNetCore.Rewrite; // Пакет с middleware URL Rewriting

var builder = WebApplication.CreateBuilder();

var app = builder.Build();

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

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

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

app.Run();

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

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