ASP.NET MVC,Url路由:最大path(URL)长度
情景
我有一个应用程序,我们采取了旧的查询stringURL结构:
?x=1&y=2&z=3&a=4&b=5&c=6
并将其改为path结构:
/x/1/y/2/z/3/a/4/b/5/c/6
我们正在使用ASP.NET MVC和(自然)ASP.NET路由。
问题
问题是我们的参数是dynamic的,并且(理论上)我们需要适应的参数数量是没有限制的。
直到我们被下列火车撞到,这一切都很好:
HTTP错误400.0 – 错误的请求ASP.NET检测到URL中的无效字符。
当我们的URL超过一定的长度时,IIS会抛出这个错误。
Nitty砂砾
以下是我们发现的:
这不是一个IIS问题
IIS确实有一个最大path长度限制,但上面的错误不是这个。
了解点iis点networking如何使用请求过滤部分“基于请求限制的filter”
如果IIS的path太长,则会抛出404.14,而不是400.0。
此外,IIS最大path(和查询)的长度是可configuration的:
<requestLimits maxAllowedContentLength="30000000" maxUrl="260" maxQueryString="25" />
这是一个ASP.NET问题
经过一番探讨:
IIS论坛主题:ASP.NET 2.0的最大URL长度? http://forums.iis.net/t/1105360.aspx
事实certificate,这是一个ASP.NET(好,.NET真的)问题。
问题的核心在于,据我所知,ASP.NET无法处理超过260个字符的path。
在棺材里的钉子,这是由菲尔哈克本人证实:
堆栈溢出ASP.NET URL MAX_PATH限制问题ID 265251
问题
那么问题是什么?
问题是,这个限制有多大?
对于我的应用程序,这是一个交易杀手。 对于大多数应用程序,这可能是一个没有问题的。
怎么披露? 没有提到ASP.NET路由的地方,我听说过这个限制的窥视。 ASP.NET MVC使用ASP.NET路由的事实使得这个影响更大。
你怎么看?
我结束了在web.config中使用以下使用Mvc2和.Net Framework 4.0来解决此问题
<httpRuntime maxUrlLength="1000" relaxedUrlToFileSystemMapping="true" />
要解决这个问题,请这样做:
在您的项目的根web.config中,在system.web节点下:
<system.web> <httpRuntime maxUrlLength="10999" maxQueryStringLength="2097151" /> ...
另外,我不得不在system.webServer节点下添加它,否则我的长查询string出现安全错误:
<system.webServer> <security> <requestFiltering> <requestLimits maxUrl="10999" maxQueryString="2097151" /> </requestFiltering> </security> ...
Http.sys服务编码默认最多为每个Url段260个字符。
这个上下文中的“url段”是Url中“/”字符之间的内容。 例如:
http://www.example.com/segment-one/segment-two/segment-three
允许的最大URL长度可以通过registry设置来更改:
- 注意:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters
- 值:
UrlSegmentMaxLength
- 键入:REG_DWORD
- 数据:(你想要的新的URL段最大允许长度,例如4096)
有关http.sys设置的更多信息: http : //support.microsoft.com/kb/820129
允许的最大值是32766.如果指定的值较大,则会被忽略。 (信用:胡安·门德斯)
重新启动电脑需要对此设置进行更改才能生效。 (信用:David Rettenbacher,胡安·门德斯)
好,所以我发布这个的原因也是因为我们find了解决办法。
我希望这对将来的某个人有用:D
解决方法
解决方法非常简单,也很好。
由于我们知道网站的哪些部分需要使用dynamic参数(因此会有一个dynamic的path和长度),所以我们可以避免在连接到ASP.NET之前通过拦截来将这个长的url发送到ASP.NET路由
inputIIS7 Url重写(或任何等效的重写模块)。
我们build立这样一个规则:
<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>
基本上,我们所做的只是保持足够的path,以便能够调用正确的下游路线。 剩下的URLpath,我们正在黑客。
URL的其余部分在哪里?
那么,当重写规则被触发时,IIS7 URL重写模块自动在请求中设置这个头部:
HTTP_X_ORIGINAL_URL
在下游,在parsingdynamicpath的应用程序部分,而不是查看path:
HttpContext.Request.Url.PathAndQuery
我们看看那个头部:
HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]
问题解决了…差不多!
麻烦
访问标题
如果你需要知道,要访问IIS7重写模块头,你可以通过两种方式来实现:
HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]
要么
HttpContext.Request.Headers["X-ORIGINAL-URL"]
修复相对path
你还会注意到,通过上面的设置,所有的相对path都会中断(用“〜”定义的URL)。
这包括使用ASP.NET MVC HtmlHelper
和UrlHelper
方法(如Url.Route("Bla")
)定义的URL。
这是访问ASP.NET MVC代码真棒。
在System.Web.Mvc.PathHelper.GenerateClientUrlInternal()
方法中,检查是否存在相同的URL Rewrite模块头(请参阅上文):
// 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的上下文中考虑相对path。
我能想到的最简单的方法是完全删除服务器variables,所以ASP.NET MVC不会find它:
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
,原因是我需要访问请求pipe道中的头值。)
希望这可以帮助!
我想你正在努力使用GET。 尝试将请求方法更改为POST,并将这些查询string参数放入请求正文中。
长URL也不能帮助search引擎优化,是吗?
现在可能没什么问题…但是这对我来说很有效(因为我没有使用aspx文件,所以我敢打赌,这可以用于MVC):
看起来硬编码的最大URL长度已经在.NET 4.0中修复了 。 特别是,现在有一个web.config
部分:
<httpRuntime maxRequestPathLength="260" maxQueryStringLength="2048" />
允许您扩展允许的URL范围。