【问题标题】:Possible Bug With ASP.NET MVC 3 Routing?ASP.NET MVC 3 路由可能存在的错误?
【发布时间】:2012-02-23 18:35:07
【问题描述】:

通常我不会在问题中添加这样的标题,但我很确定这是一个错误(或设计使然?)

我创建了一个全新的 ASP.NET MVC 3 Web 应用程序。

然后我去了 /Home/About 页面。

此页面的网址是:

http://localhost:51419/Home/About

然后我将 URL 更改为:

http://localhost:51419/(A(a))/Home/About

页面有效吗?查看路由值,controller = Home,Action = About。忽略了第一部分?

如果我查看源中的所有链接:

<link href="/(A(a))/Content/Site.css" rel="stylesheet" type="text/css" />
<script src="/(A(a))/Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
<script src="/(A(a))/Scripts/modernizr-1.7.min.js" type="text/javascript"></script>

<li><a href="/(A(a))/">Home</a></li>
<li><a href="/(A(a))/Home/About">About</a></li>

看看它是如何维护第一部分的?就像路由引擎认为它是域的一部分或其他什么?

我感觉这是 regex 的事情,因为如果我将 URL 更改为:

http://localhost:51419/(a(a))/Home/About

(例如将大写的 A 改为小写)

它是 404 的。

任何人都可以对此有所了解吗?这是一个错误还是设计使然?

【问题讨论】:

  • IMO,标题中带有“可能的错误”的帖子值得投票,这是一件罕见的事情。这个是。
  • @AndrewBarber - 我知道。 :) 我遇到这个纯属侥幸。 Google 正在索引一些带有 guid 的奇怪 URL,这是由我们的应用程序中的错误引起的。

标签: asp.net asp.net-mvc asp.net-mvc-3 asp.net-mvc-routing


【解决方案1】:

这似乎与 ASP.NET 管道中的无 Cookie 会话有关。它在处理请求时去除 CookielessHelper.cs (System.Web.Security) 中的 URL 模式:

    // This function is called for all requests -- it must be performant.
    //    In the common case (i.e. value not present in the URI, it must not
    //    look at the headers collection
    internal void RemoveCookielessValuesFromPath() 
    {
        // See if the path contains "/(XXXXX)/" 
        string   path      = _Context.Request.ClientFilePath.VirtualPathString; 
        // Optimize for the common case where there is no cookie
        if (path.IndexOf('(') == -1) { 
            return;
        }
        int      endPos    = path.LastIndexOf(")/", StringComparison.Ordinal);
        int      startPos  = (endPos > 2 ?  path.LastIndexOf("/(", endPos - 1, endPos, StringComparison.Ordinal) : -1); 

        if (startPos < 0) // pattern not found: common case, exit immediately 
            return; 

        if (_Headers == null) // Header should always be processed first 
            GetCookielessValuesFromHeader();

        // if the path contains a cookie, remove it
        if (IsValidHeader(path, startPos + 2, endPos)) 
        {
            // only set _Headers if not already set 
            if (_Headers == null) { 
                _Headers = path.Substring(startPos + 2, endPos - startPos - 2);
            } 
            // Rewrite the path
            path = path.Substring(0, startPos) + path.Substring(endPos+1);

            // remove cookie from ClientFilePath 
            _Context.Request.ClientFilePath = VirtualPath.CreateAbsolute(path);
            // get and append query string to path if it exists 
            string rawUrl = _Context.Request.RawUrl; 
            int qsIndex = rawUrl.IndexOf('?');
            if (qsIndex > -1) { 
                path = path + rawUrl.Substring(qsIndex);
            }
            // remove cookie from RawUrl
            _Context.Request.RawUrl = path; 

            if (!String.IsNullOrEmpty(_Headers)) { 
                _Context.Request.ValidateCookielessHeaderIfRequiredByConfig(_Headers); // ensure that the path doesn't contain invalid chars 
                _Context.Response.SetAppPathModifier("(" + _Headers + ")");

                // For Cassini and scenarios where aspnet_filter.dll is not used,
                // HttpRequest.FilePath also needs to have the cookie removed.
                string filePath = _Context.Request.FilePath;
                string newFilePath = _Context.Response.RemoveAppPathModifier(filePath); 
                if (!Object.ReferenceEquals(filePath, newFilePath)) {
                    _Context.RewritePath(VirtualPath.CreateAbsolute(newFilePath), 
                                         _Context.Request.PathInfoObject, 
                                         null /*newQueryString*/,
                                         false /*setClientFilePath*/); 
                }
            }
        }
    } 

你的模式符合这个:

    ///////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////// 
    // Make sure sub-string if of the pattern: A(XXXX)N(XXXXX)P(XXXXX) and so on. 
    static private bool IsValidHeader(string path, int startPos, int endPos)
    { 
        if (endPos - startPos < 3) // Minimum len is "X()"
            return false;

        while (startPos <= endPos - 3) { // Each iteration deals with one "A(XXXX)" pattern 

            if (path[startPos] < 'A' || path[startPos] > 'Z') // Make sure pattern starts with a capital letter 
                return false; 

            if (path[startPos + 1] != '(') // Make sure next char is '(' 
                return false;

            startPos += 2;
            bool found = false; 
            for (; startPos < endPos; startPos++) { // Find the ending ')'

                if (path[startPos] == ')') { // found it! 
                    startPos++; // Set position for the next pattern
                    found = true; 
                    break; // Break out of this for-loop.
                }

                if (path[startPos] == '/') { // Can't contain path separaters 
                    return false;
                } 
            } 
            if (!found)  {
                return false; // Ending ')' not found! 
            }
        }

        if (startPos < endPos) // All chars consumed? 
            return false;

        return true; 
    }

【讨论】:

  • 嗯,太……那么这是一个错误吗?不确定它是否是 ASP.NET 核心,因为该代码是有意义的。但是,ASP.NET 路由引擎(至少是 MVC 路由引擎),IMO 不应该接受它作为路由的一部分(例如它不应该匹配)。我应该向 MS 提出这个问题吗?
  • @RPM1984 不,这显然是“设计使然”,因为当 cookie 不可用时,它们如何跟踪登录的用户。假装你从未注意到这一点,一切都会好起来的。
  • @RobertLevy - 我不能忽视它。这实际上是通过实时应用程序发生在我身上的。正如我在评论中所说,谷歌正在索引一些与此模式匹配的奇怪 URL。因此,因为 MVC 接受它们作为有效路由,它们只是到达我的控制器,然后稍后死去。当他们真的应该从一开始就被 404 处理。 URL 也是随机的,所以我不能轻易地进行重写。很公平,这是 ASP.NET 的“设计”,但我认为这是 MVC 中的一个错误。它不应该接受这个作为路由。
  • 它不是随机的......它以 A( 并以以下 ) 开头,因此您可以安全地围绕它进行编码。但是,如果您进行重写,则您的网站将被禁用 cookie 的人破坏。
  • @RobertLevy - 我认为你的误解。 ASP.NET 实际上去掉了 URL 的那部分,所以当它开始我的操作时,我实际上无法在 URL 的任何部分看到它,因此无法围绕它进行编码。我认为最好的解决方案是准确计算出 ASP.NET 正在采用的正则表达式模式,然后将其作为 IIS 重写。但正如你所说,它将被破坏,因为人们将禁用 cookie。可能只需要离开它,并希望 Google 停止打击它。
【解决方案2】:

您可能想尝试将IgnoreRoute 添加到您的路由映射中 - 但我承认我不确定提供什么格式来匹配您所有可能的无 cookie 路径。

【讨论】:

    【解决方案3】:

    我同意@pjumble 的分析,但不同意他的解决方案。
    禁用表单身份验证或匿名身份验证的无 cookie 身份验证。

    这将阻止禁用 cookie 的用户进行身份验证。但谁在乎呢,现在每个人都激活了 cookie,因为没有任何现代网站都无法运行。

    在 web.config 中添加:

    <anonymousIdentification enabled="false" />
    <authentication mode="None" />
    

    <anonymousIdentification enabled="true" cookieless="UseCookies" ... />
    <authentication mode="Forms">
      <forms name="Auth" cookieless="UseCookies" ... />
    </authentication>
    

    【讨论】:

    • 顺便说一句,@pjumble 的“解决方案”是什么,我没有看到,只是一个诊断。
    • 你会因为 .net 的 url 解析中的一个愚蠢无意义的怪癖而阻止某些用户登录?
    • 竞赛:给我一个网站,它可以在禁用 cookie 的情况下 100% 正常工作。
    • @Softlion 那将是任何不使用任何会话的网站(纯信息网站)我承认它们变得越来越少,因为现在每个人都想个性化他们的网络,但它们仍然存在: -)
    • 这是一个经济问题。如果您花时间解决这个“问题”,这个功能是否比另一个您没有时间实现的功能更重要?销售部门更愿意有一个新的业务功能来销售,而不是要求与 10 个具有 nocookie 浏览器扩展的用户兼容。
    猜你喜欢
    • 1970-01-01
    • 2011-08-11
    • 1970-01-01
    • 2016-07-30
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多