Использование маршрутизации ASP.NET для обслуживания статических файлов
Может ли ASP.Net-маршрутизация (а не MVC) использоваться для статических файлов?
Скажем, я хочу маршрутизировать
http://domain.tld/static/picture.jpg
к
http://domain.tld/a/b/c/picture.jpg
и я хочу сделать это динамически в том смысле, что переписанный URL-адрес вычисляется "на лету". Я не могу настроить статический маршрут раз и навсегда.
Во всяком случае, я могу создать такой маршрут:
routes.Add(
"StaticRoute", new Route("static/{file}", new FileRouteHandler())
);
В методе FileRouteHandler.ProcessRequest
я могу переписать путь от /static/picture.jpg
до /a/b/c/picture.jpg
. Затем я хочу создать обработчик для статических файлов. Для этой цели ASP.NET использует StaticFileHandler
. К сожалению, этот класс является внутренним. Я попытался создать обработчик с использованием отражения, и он действительно работает:
Assembly assembly = Assembly.GetAssembly(typeof(IHttpHandler));
Type staticFileHandlerType = assembly.GetType("System.Web.StaticFileHandler");
ConstructorInfo constructorInfo = staticFileHandlerType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
return (IHttpHandler) constructorInfo.Invoke(null);
Но использование внутренних типов не является правильным решением. Другой вариант - реализовать собственный StaticFileHandler
, но делать это правильно (поддержка HTTP-материалов, таких как диапазоны и etags) является нетривиальным.
Как мне подойти к маршрутизации статических файлов в ASP.NET?
Ответы
Ответ 1
После прохождения этой проблемы в течение нескольких часов я обнаружил, что просто добавление правил игнорирования приведет к загрузке ваших статических файлов.
В RegisterRoutes (маршруты RouteCollection) добавьте следующие правила игнорирования:
routes.IgnoreRoute("{file}.js");
routes.IgnoreRoute("{file}.html");
Ответ 2
Почему бы не использовать IIS для этого? Вы можете просто создать правило перенаправления, чтобы указать любые запросы с первого маршрута на второй, прежде чем запрос даже попадет в ваше приложение. Из-за этого это был бы более быстрый способ перенаправления запросов.
Предполагая, что у вас есть IIS7 +, вы делаете что-то вроде...
<rule name="Redirect Static Images" stopProcessing="true">
<match url="^static/?(.*)$" />
<action type="Redirect" url="/a/b/c/{R:1}" redirectType="Permanent" />
</rule>
Или, если вам не нужно перенаправлять, как было предложено @ni5ni6:
<rule name="Rewrite Static Images" stopProcessing="true">
<match url="^static/?(.*)$" />
<action type="Rewrite" url="/a/b/c/{R:1}" />
</rule>
Редактировать 2015-06-17 для @RyanDawkins:
И если вам интересно, где находится правило перезаписи, вот карта его местоположения в файле web.config
.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<!-- rules go below -->
<rule name="Redirect Static Images" stopProcessing="true">
<match url="^static/?(.*)$" />
<action type="Redirect" url="/a/b/c/{R:1}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Ответ 3
У меня была аналогичная проблема. Я закончил использование HttpContext.RewritePath:
public class MyApplication : HttpApplication
{
private readonly Regex r = new Regex("^/static/(.*)$", RegexOptions.IgnoreCase);
public override void Init()
{
BeginRequest += OnBeginRequest;
}
protected void OnBeginRequest(object sender, EventArgs e)
{
var match = r.Match(Request.Url.AbsolutePath);
if (match.Success)
{
var fileName = match.Groups[1].Value;
Context.RewritePath(string.Format("/a/b/c/{0}", fileName));
}
}
}
Ответ 4
Я придумал альтернативу использованию внутреннего StaticFileHandler
. В IRouteHandler
я вызываю HttpServerUtility.Transfer
:
public class FileRouteHandler : IRouteHandler {
public IHttpHandler GetHttpHandler(RequestContext requestContext) {
String fileName = (String) requestContext.RouteData.Values["file"];
// Contrived example of mapping.
String routedPath = String.Format("/a/b/c/{0}", fileName);
HttpContext.Current.Server.Transfer(routedPath);
return null; // Never reached.
}
}
Это взломать. Предполагается, что IRouteHandler
возвращает IHttpHandler
, а не отменяет и передает текущий запрос. Тем не менее, он действительно достигает того, чего я хочу.
Использование внутреннего StaticFileHandler
также немного взломано, так как мне нужно отражение, чтобы получить к нему доступ, но по крайней мере есть документация на StaticFileHandler
на MSDN, что делает его немного более "официальным" классом. К сожалению, я не думаю, что можно подумать о внутренних классах в частичной среде доверия.
Я буду придерживаться использования StaticFileHandler
, поскольку я не думаю, что он удаляется из ASP.NET в обозримом будущем.
Ответ 5
Вам необходимо добавить TransferRequestHandler для обработки ваших статических файлов. Пожалуйста, см. следующий ответ
fooobar.com/info/90741/...