76

可以使用 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.jpgto的路径/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,但正确地实现(支持范围和 etag 等 HTTP 内容)并非易事。

我应该如何在 ASP.NET 中处理静态文件的路由?

4

5 回答 5

57

为什么不使用 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>

为@RyanDawkins 编辑 2015-06-17

如果你想知道重写规则的去向,这里是它在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>
于 2009-07-26T18:16:27.403 回答
39

在研究了这个问题几个小时后,我发现只需添加忽略规则即可获得静态文件。

在 RegisterRoutes(RouteCollection routes) 中,添加以下忽略规则:

routes.IgnoreRoute("{file}.js");
routes.IgnoreRoute("{file}.html");
于 2010-06-24T17:02:51.160 回答
13

我有一个类似的问题。我最终使用了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));
        }
    }
}
于 2010-10-17T06:26:23.933 回答
7

我想出了使用 internal 的替代方法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也有点 hack,因为我需要反射才能访问它,但至少在 MSDN上有一些文档StaticFileHandler使它成为一个稍微“官方”的类。不幸的是,我认为不可能在部分信任环境中反映内部类。

我会坚持使用StaticFileHandler,因为我认为在可预见的将来它不会从 ASP.NET 中删除。

于 2009-08-24T09:04:49.997 回答
4

您需要添加 TransferRequestHandler 来处理您的静态文件。请参阅以下答案 https://stackoverflow.com/a/21724783/22858

于 2014-02-12T10:19:38.987 回答