好的,我发布这篇文章的原因之一是因为我们找到了一个解决方法。
我希望这对将来的某些人有用 :D
解决方法
这个解决方法非常简单,也很好用。
既然我们知道网站的哪些部分需要使用动态参数(因此会具有动态路径和长度),我们就可以在它到达 ASP.NET 之前拦截它,从而避免将这个长URL发送给 ASP.NET 路由。
输入 IIS7 Url 重写(或任何等效的重写模块)。
我们设置了如下规则:
<rewrite>
<rules>
<rule>
<rule name="Remove Category Request Parameters From Url">
<match url="^category/(\d+)/{0,1}(.*)$" />
<action type="Rewrite" url="category/{R:1}" />
</rule>
</rules>
</rewrite>
基本上,我们所做的只是保留足够的路径来调用下游的正确路由。我们要砍掉URL路径的其余部分。
剩下的URL路径去哪里了?
好吧,当重写规则被触发时,IIS7 URL Rewrite模块会自动在请求中设置此标题:
HTTP_X_ORIGINAL_URL
在应用程序的下游部分解析动态路径时,不要查看路径,而是:
HttpContext.Request.Url.PathAndQuery
我们来看一下那个标题:
HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]
问题解决了……几乎!
问题
访问标题
如果您需要知道,要访问IIS7 Rewrite模块标头,有两种方法:
HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]
或者
HttpContext.Request.Headers["X-ORIGINAL-URL"]
修复相对路径
您还会注意到,在上述设置中,所有相对路径(使用“~”定义的URL)都会失效。
这包括使用ASP.NET MVC的HtmlHelper
和UrlHelper
方法定义的URL(例如Url.Route("Bla")
)。
这就是可以访问ASP.NET MVC代码的好处所在。
在System.Web.Mvc.PathHelper.GenerateClientUrlInternal()
方法中,有一个检查是否存在相同的URL转发模块头(见上文):
// we only want to manipulate the path if URL rewriting is active, else we risk breaking the generated URL
NameValueCollection serverVars = httpContext.Request.ServerVariables;
bool urlRewriterIsEnabled = (serverVars != null && serverVars[_urlRewriterServerVar] != null);
if (!urlRewriterIsEnabled) {
return contentPath;
}
如果发生URL改写,有些工作需要做来保留原始的URL。
在我们的情况下,由于我们没有以“正常”方式使用URL重写,我们希望绕过这个过程。
我们想要假装没有发生URL改写,因为我们不希望将相对路径视为原始URL上下文的一部分。
我能想到的最简单的方法是完全删除该服务器变量,这样ASP.NET MVC就找不到它了。
protected void Application_BeginRequest()
{
string iis7UrlRewriteServerVariable = "HTTP_X_ORIGINAL_URL";
string headerValue = Request.ServerVariables[iis7UrlRewriteServerVariable];
if (String.IsNullOrEmpty(headerValue) == false)
{
Request.ServerVariables.Remove(iis7UrlRewriteServerVariable);
Context.Items.Add(iis7UrlRewriteServerVariable, headerValue);
}
}
(注意,在上面的方法中,我从
Request.ServerVariables
中删除了标头,但仍然保留它,并将其存储在
Context.Items
中。这样做的原因是我需要在请求管道的后续阶段访问标头值。)
希望这可以帮助您!