RedirectToAction()中断元音变音符

本文关键字:音符 中断 RedirectToAction | 更新日期: 2023-09-27 18:25:22

注意:导致问题的不是RedirectToAction(),而是重写web.config 中的规则

原始问题:使用RedirectToAction()时有一种奇怪的行为,我无法在本地重现(调试)。在某个时刻,我的路由值从äa更改为äa,但仅在服务器(Azure)上更改。我添加了日志记录来精确定位位置,最后出现在这里:

RedirectToAction("square", new { id = criteria.Trim().ToLower() });

在本地,它会正确重定向到/find/square/äa,但在服务器上,它最终会重定向到/find/square/äa。我记录了每一步,当我的字符串被传递到RedirectToAction时,它仍然完好无损(即使在Trim()ToLower()之后),但在重定向后被破坏了。我使用默认路线

routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional }

具有控制器find、动作square和id äa(在这种情况下)

这让我非常惊讶,因为.NET在元音变音符和UTF-8方面通常非常谨慎和健壮。我在这里特别失落,因为我无法在当地重现这个问题。我认为这是一个服务器设置,但Azure在这一点上相当稀疏。以前有人经历过类似的行为吗?

RedirectToAction()中断元音变音符

这是我代码中没有发布的一部分,重写规则。我是在仔细查看Fiddler中的重定向后才发现的。事实上,在我故意触发的重定向之后,我发现了一个额外的重定向,它是由我的一个重写规则引起的:

    <rule name="Lowercase Path" stopProcessing="true" >
      <match url="[A-Z]" ignoreCase="false" />
      <conditions>
        <add input="{REQUEST_METHOD}" matchType="Pattern" pattern="POST" ignoreCase="true" negate="true" />
        <add input="{URL}" pattern="^.*'.(axd|css|js|jpg|jpeg|png|gif|txt|xml|svg|pdf)$" negate="true" ignoreCase="true" />
      </conditions>
      <action type="Redirect" url="{tolower:{URL}}" redirectType="Permanent" />
    </rule>

事实上,它是以下行:

<action type="Redirect" url="{tolower:{URL}}" redirectType="Permanent" />

一旦我禁用此规则,一切都会正常工作。我的其他不使用{ToLower:}的规则没有产生任何问题。我不确定,为什么这不会破坏当地的东西。在进行研究时,我发现了一篇文章,描述了微软如何修补一个损坏的重写模块,该模块导致了元音变音符的类似问题。这只是猜测,但也许我的azure实例上的重写版本是未修补的——或者它是完全不同的。

不幸的是,除了在{tolower:{URL}}中使用重写规则之外,几乎没有其他选择,所以我不得不做一个相当丑陋的变通方法,在Global.asax.cs中检查我的URL,如下所示:

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        var pathAndQuery = System.Web.HttpUtility.UrlDecode(Request.Url.PathAndQuery);
        if (pathAndQuery == null || Regex.IsMatch(pathAndQuery, @"^.*'.(axd|css|js|jpg|jpeg|png|gif|txt|xml|svg|pdf)$"))
        {
            return;
        }
        if (Regex.IsMatch(pathAndQuery, ".*[A-Z].*"))
        {
            Response.Redirect(pathAndQuery.ToLower(), false);
            Response.StatusCode = 301;
        }
    }

我对这种方法并不完全满意;它感觉很臭,但在我找到更好的解决方案之前,这就足够了。