使用ASP.NET路由来提供静态文件
ASP.Net路由(而不是MVC)可以用来提供静态文件吗?
说我想要路线
http://domain.tld/static/picture.jpg
至
http://domain.tld/a/b/c/picture.jpg
而且我想dynamic地执行,因为重写的URL是即时计算的。 我无法一劳永逸地设置一条静态路由。
无论如何,我可以创build一个这样的路线:
routes.Add( "StaticRoute", new Route("static/{file}", new FileRouteHandler()) );
在FileRouteHandler.ProcessRequest
方法中,我可以重写从/static/picture.jpg
到/a/b/c/picture.jpg
的path。 然后我想为静态文件创build一个处理程序。 ASP.NET为此使用StaticFileHandler
。 不幸的是,这个class是内部的。 我试图创build使用reflection处理程序,它实际上工作:
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);
但是使用内部types似乎不是合适的解决scheme。 另一个select是实现我自己的StaticFileHandler
,但是正确地执行(支持范围和etags之类的HTTP内容)并不重要。
我应该如何处理ASP.NET中的静态文件的路由?
在深入了解这个问题几个小时后,我发现只需添加忽略规则就可以获得静态文件。
在RegisterRoutes(RouteCollection路由)中,添加以下忽略规则:
routes.IgnoreRoute("{file}.js"); routes.IgnoreRoute("{file}.html");
为什么不使用IIS来做到这一点? 您可以创buildredirect规则,以便在请求甚至到达您的应用程序之前将来自第一条path的请求指向第二条path。 因此,这将是一个更快的redirect请求的方法。
假设你有IIS7 +,你可以做类似…
<rule name="Redirect Static Images" stopProcessing="true"> <match url="^static/?(.*)$" /> <action type="Redirect" url="/a/b/c/{R:1}" redirectType="Permanent" /> </rule>
或者 ,如果你不需要redirect,就像@ ni5ni6build议的那样:
<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
文件中find它的位置。
<?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>
我有类似的问题。 我结束了使用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)); } } }
我想出了一个使用内部StaticFileHandler
的替代scheme。 在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
也是一个黑客,因为我需要reflection来访问它,但是至less在MSDN上有一些关于StaticFileHandler
文档,使它成为一个稍微更“官方”的类。 不幸的是,我不认为有可能在部分信任环境中反思内部类。
我将坚持使用StaticFileHandler
因为我不认为它会在可预见的将来从ASP.NET中删除。
你需要添加TransferRequestHandler来处理你的静态文件。请看下面的回答https://stackoverflow.com/a/21724783/22858