如何确保POST上的小写URL?

时间:2010-12-03 20:30:25

标签: asp.net-mvc seo url-rewriting url-routing

我正在尝试确保用于访问我的ASP.NET MVC站点的所有URL都是小写的。如果URL中包含大写字母,我将状态代码更改为301,并使用以下代码将位置更改为URL的小写版本:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    var url = Request.Url.ToString();
    if (Regex.IsMatch(url, @"[A-Z]"))
    {
       Response.Clear();
       Response.Status = "301 Moved Permanently";
       Response.StatusCode = (int)HttpStatusCode.MovedPermanently;
       Response.AddHeader("Location", url.ToLower());
       Response.End();
     }
}

然而,最近一位同事试图将表单发布到带有大写字母的URL(忘记重定向),但是操作(标有HttpPost属性)没有被命中。查看Firebug中的请求显示了原始POST,但随后它返回301并向小写版本发出了GET。

我猜最好的解决方案就是确保所有的POST都是URL的小写版本,但我来到这里是为了看看是否有另一种方法来处理这个问题

5 个答案:

答案 0 :(得分:3)

您可以为路由创建一个扩展方法,该方法将呈现所有网址的小写:

守则:

 public class LowercaseRoute : System.Web.Routing.Route
    {
        public LowercaseRoute(string url, IRouteHandler routeHandler) : base(url, routeHandler) { }
        public LowercaseRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler) : base(url, defaults, routeHandler) { }
        public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler) : base(url, defaults, constraints, routeHandler) { }
        public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler) : base(url, defaults, constraints, dataTokens, routeHandler) { }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            VirtualPathData path = base.GetVirtualPath(requestContext, values);

            if (path != null)
                path.VirtualPath = path.VirtualPath.ToLowerInvariant();

            return path;
        }
    }

    public static class RouteCollectionExtensions
    {
        public static void MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults)
        {
            routes.MapRouteLowercase(name, url, defaults, null);
        }

        public static void MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults, object constraints)
        {
            Check.Argument.IsNotNull(routes, "routs");
            Check.Argument.IsNotNull(url, "url");

            var route = new LowercaseRoute(url, new MvcRouteHandler())
            {
                Defaults = new RouteValueDictionary(defaults),
                Constraints = new RouteValueDictionary(constraints)
            };

            if (String.IsNullOrEmpty(name))
                routes.Add(route);
            else
                routes.Add(name, route);
        }
    }

您的路线:

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

现在,当您使用... Html.BeginForm()...时,它将呈现操作的小写URL。每当您使用路由来呈现链接时,这也将始终呈现小写URL,即Url.Action(); <%:Html.RenderAction()%>

答案 1 :(得分:1)

正如朱塞佩指出的那样,搜索引擎不会对POST页面进行索引。我最终得到了这个:

protected void Application_BeginRequest(object sender, EventArgs e)
{
  if(Request.HttpMethod == "POST") return;

  //etc
}

答案 2 :(得分:1)

这是一个基于scottm解决方案的版本,适用于.NET 4.0

protected void Application_BeginRequest(object sender, EventArgs e) {
    string url = Request.Url.ToString();
    if (Request.HttpMethod == "GET" && Regex.Match(url, "[A-Z]").Success) {
        Response.RedirectPermanent(url.ToLower(), true);
    }
}

答案 3 :(得分:0)

根据我的理解,没有办法强制用户重新发出POST请求。您只能重定向它们,并且这样做只会指定一个URL(而不是POST数据)。

对我来说,更大的问题是:为什么你如此坚持不拥有大写的URL? HTTP指定URLS不区分大小写。

答案 4 :(得分:0)

扩展@bingles很棒的答案,也许你不想强制GET数据小写?然后,您可能希望使用正则表达式(?<=^[^?]*)[A-Z]

protected void Application_BeginRequest(object sender, EventArgs e)
{
    string url = Request.Url.ToString();
    if (Request.HttpMethod == "GET" && Regex.Match(url, "(?<=^[^?]*)[A-Z]").Success)
    {
            Response.RedirectPermanent(url.ToLower(), true);
    }
}

正则表达式取自另一个答案:regex to match all uppercase letters before the first question mark