代码之家  ›  专栏  ›  技术社区  ›  SelAromDotNet

重定向asp。net core 2.0 URL小写

  •  13
  • SelAromDotNet  · 技术社区  · 8 年前

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

    使用此选项:

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

    然而,尽管这对生成url很好,但似乎并没有做任何实际的强制执行,也就是说,将所有不全是小写的url重定向到相应的小写url(最好通过301重定向)。

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

    通过RewriteOptions和Regex执行标准重定向是唯一的方法吗?要做到这一点,合适的表达方式是什么:

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

    还是有其他方法?

    5 回复  |  直到 8 年前
        1
  •  11
  •   Stefano Sansone    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.Value + request.Path.Value).ToLower() + request.QueryString;
                context.Result = RuleResult.EndResponse; 
            }
            else
            {
                context.Result = RuleResult.ContinueRules;
            } 
        }
    }
    

    然后可以将其应用于 Startup.cs 在下面 Configure 方法如下:

    new RewriteOptions().Add(new RedirectLowerCaseRule());
    
        2
  •  0
  •   Brian Tompsett - 汤莱恩 andrewwong97    7 年前

    添加为答案,因为我还不能发表评论。这是对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;
            }
        }
    }
    
        3
  •  0
  •   zed    7 年前

    略有不同的实现,也受到 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 .

        4
  •  0
  •   James Law    6 年前

    我的两分钱。。。基于 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 to POST),但是如果您想允许这种行为,可以使用301和302。看见 What's the difference between HTTP 301 and 308 status codes? 了解更多信息。

        5
  •  -2
  •   Herb Stahl    7 年前

    确实要重定向吗?如果没有,并且您的目标是在主机和路径中没有大写,那么您可以使用以下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()));
        ...
    }