Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core 7
Если необходимо использовать какую-то более сложную логику по переопределению строки запроса, то в этом случае мы можем определить свои правила с помощью методов или целых классов.
Например, пусть ранее сайт использовал технологию php, но затем мигрировал на asp.net, а все документы php были сконвертированы в документы html. То есть ранее сайт, к примеру, использовал адрес http://localhost:1234/some.php, то теперь документ перемещен по адресу http://localhost:1234/html/some.html. Расмотрим на примере создания своих правил, как мы можем решить проблему адресов.
Пусть нужные документы находятся в проекте в папке webroot/html:
Допустим, там находится следующая страница 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:
В этом случае произойдет обращение к документу 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,