使用 ASP.NET 路由来提供静态文件

Posted

技术标签:

【中文标题】使用 ASP.NET 路由来提供静态文件【英文标题】:Using ASP.NET routing to serve static files 【发布时间】:2010-11-12 02:15:33 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

我也更喜欢这种方法。我认为,将其移至管道并让 IIS 工作进程处理重定向比通过运行时实际处理路由的旋转周期更有效。即使服务器上的流失量大致相同,我也会走不使用路由的路线(双关语)并将重定向保持在应用程序本身之外。 从我最初的问题版本中不清楚的是,重写的 URL 是动态计算的(我不关心这里的性能)。我已经更新了问题以澄清这一点。无论如何,感谢您的回复。 (删除了我之前的评论并重新添加了一个非缩短的 url)。 Martin,抛开性能问题不谈,你为什么要在应用程序中处理这个 url,而在外面处理它会更好?我想您可以创建一个控制器操作来处理此问题,但您可以看看以下内容:- geekswithblogs.net/sankarsan/archive/2009/01/18/… @RyanDawkins 在 web.config 中。有关其确切位置的更多信息,请参阅我的编辑。 很好的答案,第一次工作。现在这种情况并不经常发生!【参考方案2】:

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

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

【讨论】:

【参考方案3】:

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

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

routes.IgnoreRoute("file.js");
routes.IgnoreRoute("file.html");

【讨论】:

对我来说它可以工作,但我无法解析区域的视图文件夹中的 JS 文件,为了解决这个问题,我使用区域基本文件夹中的另一个文件夹,例如 /Areas/ MyArea/ClientScripts/foo.js 不知怎的,我似乎错过了拼图中的一块......忽略到静态文件的路由如何帮助路由从/static/a/b/c(OP 要求)?您能否进一步说明您的答案,我真的很想了解这个解决方案。 同意 Oliver 的观点,即这不能回答 OP,不应被接受为解决方案。 如果您需要您的 MVC 控制器在路由之前先检查用户是否登录,该怎么办?忽略路由与重定向到静态文件夹结构不同。 添加 robots.txt 的最简单方法【参考方案4】:

我也遇到过类似的问题。我最终使用了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));
        
    

【讨论】:

非常感谢分享这个。在本地开发期间遇到这个寻找 URL Rewrite 的解决方案,并意识到我可以在任何地方这样做。我用它不是用于输入解析,而是用于 JS 和 CSS 文件版本管理。 对于任何有兴趣的人,为了管理filename.v1234.js 形式的文件,我使用private readonly Regex regJS = new Regex("^(.*)([.]v[0-9]+)([.](js|css))$", RegexOptions.IgnoreCase);,然后在匹配时使用Context.RewritePath(string.Format("01", matchJS.Groups[1].Value, matchJS.Groups[3].Value));【参考方案5】:

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

【讨论】:

以上是关于使用 ASP.NET 路由来提供静态文件的主要内容,如果未能解决你的问题,请参考以下文章

将静态文件路由到 asp.net mvc 中的新路径

ASP.NET Core使用静态文件目录游览与MIME类型管理

asp.net core 系列之静态文件

如何在 ASP.NET MVC 的 ~/Views 文件夹下请求静态 .html 文件?

如何使用目录名称中的句点从 Asp .Net Core 提供静态文件

防止 IIS 通过 ASP.NET 管道提供静态文件