【问题标题】:Redirect asp.net core 2.0 urls to lowercase将 asp.net core 2.0 url 重定向为小写
【发布时间】:2018-07-06 06:20:52
【问题描述】:

我看到您可以在 ASP.NET Core 2.0 中配置路由以生成小写 URL,如下所述:https://stackoverflow.com/a/45777372/83825

使用这个:

services.AddRouting(options => options.LowercaseUrls = true);

然而,虽然生成 url 很好,但它似乎并没有做任何事情来实际执行它们,也就是说,将所有不是全小写的 url 重定向到相应的小写 url(最好通过 301 重定向)。

我知道人们通过不同大小写的网址访问我的网站,我希望它们都永久小写。

通过 RewriteOptions 和 Regex 进行标准重定向是唯一的方法吗?什么是合适的表达方式:

var options = new RewriteOptions().AddRedirect("???", "????");

或者还有其他方法吗?

【问题讨论】:

    标签: url-redirection asp.net-core-2.0 lowercase


    【解决方案1】:

    我的两分钱...基于https://github.com/aspnet/AspNetCore/blob/master/src/Middleware/Rewrite/src/RedirectToWwwRule.cs

    public class RedirectToLowercaseRule : IRule
    {
        private readonly int _statusCode;
    
        public RedirectToLowercaseRule(int statusCode)
        {
            _statusCode = statusCode;
        }
    
        public void ApplyRule(RewriteContext context)
        {
            var req = context.HttpContext.Request;
    
            if (!req.Scheme.Any(char.IsUpper)
                && !req.Host.Value.Any(char.IsUpper)
                && !req.PathBase.Value.Any(char.IsUpper)
                && !req.Path.Value.Any(char.IsUpper))
            {
                context.Result = RuleResult.ContinueRules;
                return;
            }
    
            var newUrl = UriHelper.BuildAbsolute(req.Scheme.ToLowerInvariant(), new HostString(req.Host.Value.ToLowerInvariant()), req.PathBase.Value.ToLowerInvariant(), req.Path.Value.ToLowerInvariant(), req.QueryString);
    
            var response = context.HttpContext.Response;
            response.StatusCode = _statusCode;
            response.Headers[HeaderNames.Location] = newUrl;
            context.Result = RuleResult.EndResponse;
            context.Logger.RedirectedToLowercase();
        }
    }
    

    使用扩展方法:

    public static class RewriteOptionsExtensions
    {
        public static RewriteOptions AddRedirectToLowercase(this RewriteOptions options, int statusCode)
        {
            options.Add(new RedirectToLowercaseRule(statusCode));
            return options;
        }
    
        public static RewriteOptions AddRedirectToLowercase(this RewriteOptions options)
        {
            return AddRedirectToLowercase(options, StatusCodes.Status307TemporaryRedirect);
        }
    
        public static RewriteOptions AddRedirectToLowercasePermanent(this RewriteOptions options)
        {
            return AddRedirectToLowercase(options, StatusCodes.Status308PermanentRedirect);
        }
    }
    

    和日志记录:

    internal static class MiddlewareLoggingExtensions
    {
        private static readonly Action<ILogger, Exception> _redirectedToLowercase = LoggerMessage.Define(LogLevel.Information, new EventId(1, "RedirectedToLowercase"), "Request redirected to lowercase");
    
        public static void RedirectedToLowercase(this ILogger logger)
        {
            _redirectedToLowercase(logger, null);
        }
    }
    

    及用法:

    app.UseRewriter(new RewriteOptions()
        .AddRedirectToLowercase());
    

    其他注意事项是状态代码的选择。我在扩展方法中使用了 307 和 308,因为它们可以防止在请求期间更改请求方法(例如从 GET 到 POST),但是如果你想允许这种行为,你可以使用 301 和 302。请参阅What's the difference between HTTP 301 and 308 status codes? 了解更多信息。

    【讨论】:

      【解决方案2】:

      略有不同的实现,同样受到this other thread的启发。

      public class RedirectLowerCaseRule : IRule
      {
          public void ApplyRule(RewriteContext context)
          {
              HttpRequest request = context.HttpContext.Request;
              string url = request.Scheme + "://" + request.Host + request.PathBase + request.Path;
              bool isGet = request.Method.ToLowerInvariant().Contains("get");
      
              if ( isGet && url.Contains(".") == false && Regex.IsMatch(url, @"[A-Z]") )
              {
                  HttpResponse response = context.HttpContext.Response;
                  response.Clear();
                  response.StatusCode = StatusCodes.Status301MovedPermanently;
                  response.Headers[HeaderNames.Location] = url.ToLowerInvariant() + request.QueryString;
                  context.Result = RuleResult.EndResponse;
              }
              else
              {
                  context.Result = RuleResult.ContinueRules;
              }
          }
      }
      

      我认为有用的更改:
      使用ToLowerInvariant() 而不是ToLower()(查看可能的问题here
      保留端口号。
      绕过 GET 以外的请求方法。
      使用点绕过请求,假设像 js/css/images 等静态文件应该保留所有大写字母。
      使用Microsoft.AspNetCore.Http.StatusCodes

      【讨论】:

        【解决方案3】:

        添加为答案,因为我不能评论(还)。这是对 Ben Maxfields 答案的补充。

        使用他的代码http://www.example.org/Example/example 不会被重定向,因为PathBase 没有检查大写字母(即使它用于构建新的小写URI)。

        所以根据他的代码,我最终使用了这个:

        public class RedirectLowerCaseRule : IRule
        {
            public int StatusCode { get; } = (int)HttpStatusCode.MovedPermanently;
        
            public void ApplyRule(RewriteContext context)
            {
                HttpRequest request = context.HttpContext.Request;
                PathString path = context.HttpContext.Request.Path;
                PathString pathbase = context.HttpContext.Request.PathBase;
                HostString host = context.HttpContext.Request.Host;
        
                if ((path.HasValue && path.Value.Any(char.IsUpper)) || (host.HasValue && host.Value.Any(char.IsUpper)) || (pathbase.HasValue && pathbase.Value.Any(char.IsUpper)))
                {
                    Console.WriteLine("Redirect should happen");
        
                    HttpResponse response = context.HttpContext.Response;
                    response.StatusCode = StatusCode;
                    response.Headers[HeaderNames.Location] = (request.Scheme + "://" + host.Value + request.PathBase + request.Path).ToLower() + request.QueryString;
                    context.Result = RuleResult.EndResponse;
                }
                else
                {
                    context.Result = RuleResult.ContinueRules;
                }
            }
        }
        

        【讨论】:

        • 请不要添加“谢谢”作为答案。一旦你有足够的reputation,你就可以vote up questions and answers你觉得有帮助。 - From Review
        • 感谢您对贝尔伍德的评论!我编辑了我的答案。它现在看起来不像评论了,我添加了一个例子。
        【解决方案4】:

        感谢这已经有好几个月了,但是对于可能正在寻找相同解决方案的人,您可以添加一个复杂的重定向来实现 IRule,例如:

        public class RedirectLowerCaseRule : IRule
        {
            public int StatusCode { get; } = (int)HttpStatusCode.MovedPermanently;
        
            public void ApplyRule(RewriteContext context)
            {
                HttpRequest request = context.HttpContext.Request;
                PathString path = context.HttpContext.Request.Path;
                HostString host = context.HttpContext.Request.Host;
        
                if (path.HasValue && path.Value.Any(char.IsUpper) || host.HasValue && host.Value.Any(char.IsUpper))
                {
                    HttpResponse response = context.HttpContext.Response;
                    response.StatusCode = StatusCode;
                    response.Headers[HeaderNames.Location] = (request.Scheme + "://" + host.Value + request.PathBase + request.Path).ToLower() + request.QueryString;
                    context.Result = RuleResult.EndResponse; 
                }
                else
                {
                    context.Result = RuleResult.ContinueRules;
                } 
            }
        }
        

        这可以在 Startup.cs 下的 Configure 方法中应用,如下所示:

        new RewriteOptions().Add(new RedirectLowerCaseRule());
        

        希望这会有所帮助!

        【讨论】:

        • Microsoft.AspNetCore.Http 有一个StatusCodes 枚举,您可以使用它来代替(int)HttpStatusCode.XXX。它们在每个枚举名称中包含状态代码编号,例如,StatusCodes.Status301MovedPermanently
        • 您不想小写 request.QueryString()。这将包含合法的大写值。
        【解决方案5】:

        您确定要重定向吗?如果没有,并且您的目标是在您的主机和路径中没有大写这样的东西,您可以使用以下 IRule。这向我保证,无论我在哪里查看管道中的路径,它都是小写的。

        public class RewriteLowerCaseRule : IRule
        {
            public void ApplyRule(RewriteContext context)
            {
                var request = context.HttpContext.Request;
                var host = request.Host;
                var pathBase = request.PathBase;
                var path = request.Path;
                if (host.HasValue)
                {
                    if (host.Port == null)
                    {
                        request.Host = new HostString(host.Host.ToLower());
                    }
                    else
                    {
                        request.Host = new HostString(host.Host.ToLower(), (int) host.Port);
                    }
                }
        
                if (pathBase.HasValue)
                {
                    request.PathBase = new PathString(pathBase.Value.ToLower());
                }
        
                if (path.HasValue)
                {
                    request.Path = new PathString(path.Value.ToLower());
                    request.PathBase = new PathString(pathBase.Value.ToLower());
                }
        
                context.Result = RuleResult.ContinueRules;
            }
        }
        

        用法:

        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            app.UseRewriter(new RewriteOptions().Add(new RewriteLowerCaseRule()));
            ...
        }
        

        【讨论】:

        • 问题明确指出需要将包含任何大写字符的 url 永久 301 重定向到小写。这个答案没有做到这一点,也没有真正提供比上一个答案中的任何新的东西。我也不确定在什么情况下您需要使用非强制小写 url,但在后端访问它们时强制使用小写,这似乎有点代码味道,可能会导致难以找到问题如果团队中的其他开发人员忘记或不知道该行。
        • 这是一个非常好的替代问题试图完成的内容。该站点正在执行代码以评估输入的内容是否为大写,然后通过发出浪费的永久重定向进一步浪费互联网资源,然后再次评估它以确保。知道不可能阻止大写请求进入,站点应该吃掉它,修复它,然后让请求通过。所以这里的正确答案是不要做永久重定向。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-23
        相关资源
        最近更新 更多