【问题标题】:Redirect Non WWW to WWW using Asp.Net Core Middleware使用 Asp.Net Core 中间件将非 WWW 重定向到 WWW
【发布时间】:2017-10-05 00:36:54
【问题描述】:

在 ASP.Net Core 应用程序启动时,我有:

RewriteOptions rewriteOptions = new RewriteOptions(); 

rewriteOptions.AddRedirectToHttps();

applicationBuilder.UseRewriter(rewriteOptions);

在生产中,我需要将所有非 WWW 重定向到 WWW 网址

例如:

domain.com/about > www.domain.com/about

如何使用重写中间件做到这一点?

我认为这可以使用 AddRedirect 和 Regex 来完成:

Github - ASP.NET Core Redirect Docs

但不知道怎么做...

【问题讨论】:

  • AddApacheModRewrite 在这种情况下有效吗?

标签: regex asp.net-core url-rewriting asp.net-core-middleware


【解决方案1】:

可重用的替代方法是创建自定义重写规则和相应的扩展方法,以将规则添加到重写选项。这与 AddRedirectToHttps 的工作方式非常相似。

自定义规则:

public class RedirectToWwwRule : IRule
{
    public virtual void ApplyRule(RewriteContext context)
    {
        var req = context.HttpContext.Request;
        if (req.Host.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase))
        {
            context.Result = RuleResult.ContinueRules;
            return;
        }

        if (req.Host.Value.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
        {
            context.Result = RuleResult.ContinueRules;
            return;
        }

        var wwwHost = new HostString($"www.{req.Host.Value}");
        var newUrl = UriHelper.BuildAbsolute(req.Scheme, wwwHost, req.PathBase, req.Path, req.QueryString);
        var response = context.HttpContext.Response;
        response.StatusCode = 301;
        response.Headers[HeaderNames.Location] = newUrl;
        context.Result = RuleResult.EndResponse;
    }
}

扩展方法:

public static class RewriteOptionsExtensions
{
    public static RewriteOptions AddRedirectToWww(this RewriteOptions options)
    {
        options.Rules.Add(new RedirectToWwwRule());
        return options;
    }
}

用法:

var options = new RewriteOptions();
options.AddRedirectToWww();
options.AddRedirectToHttps();
app.UseRewriter(options);

重写中间件的未来版本将包含规则和相应的扩展方法。见this pull request

【讨论】:

  • 如果您希望您的应用程序处理不同的子域,它是否打算仅使用 PR 从无子域重定向到 www?所以例如mydomain.org 转到 www.mydomain.org,但 ww2.mydomain.org 保持不变?
【解决方案2】:

我更像是一个 Apache 用户,幸运的是 ASP.NET Core 中的 URL 重写中间件提供了一个名为 AddApacheModRewrite 的方法来即时执行 mod_rewrite 规则。

1- 创建一个.txt 文件,无论名称如何,并将这两行放入其中:

RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]

2-然后这样称呼它:

AddApacheModRewrite(env.ContentRootFileProvider, "Rules.txt")

完成!

【讨论】:

    【解决方案3】:

    只使用一个正则表达式,

    找到^(https?://)?((?!www\.)(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))

    替换$1www.$2

    展开

     ^                             # BOS
     (                             # (1 start), optional http(s)
          https?  ://
     )?                            # (1 end)
     (                             # (2 start), domains without www prefix
          (?! www\. )
          (?:
               (?: [a-z\u00a1-\uffff0-9]+ -? )*
               [a-z\u00a1-\uffff0-9]+ 
          )
          (?:
               \.
               (?: [a-z\u00a1-\uffff0-9]+ -? )*
               [a-z\u00a1-\uffff0-9]+ 
          )*
          (?:
               \.
               (?: [a-z\u00a1-\uffff]{2,} )
          )
     )                             # (2 end)
    

    【讨论】:

    • 这个正则表达式解决方案看起来不错,但与 ASP 重写中间件没有任何关系,并且 OP 在赏金之前有类似的基于正则表达式的解决方案。
    【解决方案4】:

    自 ASP.NET Core 3.0 (2019) 起,可以使用以下方法:

    • AddRedirectToWwwPermanent()
    • AddRedirectToWww()

    示例

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

    https://docs.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-5.0

    【讨论】:

    • app.UseRewriter(new RewriteOptions().AddRedirectToWwwPermanent());对于永久重定向,请使用此。
    【解决方案5】:

    尚不清楚 AddRedirect 方法是否执行以及它是否真的接受正则表达式。

    但是要在没有“www”的网址中插入“www”?
    您可以使用以下字符串进行尝试:

    string pattern = @"^(https?://)(?!www[.])(.*)$";
    string replacement = "$1www.$2";
    
    //Regex rgx = new Regex(pattern);
    //string redirectUrl = rgx.Replace(url, replacement);
    

    由于协议后面的负前瞻(?!www[.]),它会忽略像http://www.what.ever这样的字符串

    $1 和 $2 是第一个和第二个捕获组。

    【讨论】:

    • 看起来不错,但是如果您可以匹配和替换起始字符,为什么还要匹配整个 URL? string pattern = @"^https?://(?!www[.])";string replacement = "$&www.";
    • @JohanWentholt 好吧,我想我当时不确定正则表达式引擎是否会使用 $& 或 $0 进行匹配。但你的版本是更好的高尔夫。看到这家伙现在对这么老的问题投入巨资,我有点惊讶。哦,没关系,他改变了问题。也许他应该刚刚开始一个新的......
    【解决方案6】:

    我认为,除非必须,否则不要使用正则表达式,您可以使用 Uri 类来重构您的网址

    var uri = new Uri("http://example.com/test/page.html?query=new&sortOrder=ASC");
    var returnUri = $"{uri.Scheme}://www.{uri.Authority}
    {string.Join(string.Empty, uri.Segments)}{uri.Query}";
    

    结果会是这样的

    Output: http://www.example.com/test/page.html?query=new&sortOrder=ASC
    

    【讨论】:

    • 我需要使用正则表达式,因为这是在 ASP.NET Core 方法中使用的。
    【解决方案7】:

    这是一个可以尝试的正则表达式:

    (http)(s)?(:\/\/)[^www.][A-z0-9]+(.com|.gov|.org)
    

    它将选择如下 URL:

    • http://example.com
    • https://example.com
    • http://example.gov
    • https://example.gov
    • http://example.org
    • https://example.org

    但不喜欢:

    • http://www.example.com
    • https://www.example.com

    如果可能,我更喜欢使用显式扩展(例如.com.gov.org),但如果它对您的用例有益,您也可以使用类似的扩展:

    (http)(s)?(:\/\/)[^www.][A-z0-9]+(.*){3}
    

    然后我会用类似以下的方式来处理替换:

    Regex r = new Regex(@"(http)(s)?(:\/\/)[^www.][A-z0-9]+(.*){3}");
    string test = @"http://example.org";
    if (r.IsMatch(test))
    {
        Console.WriteLine(test.Replace("https://", "https://www."));
        Console.WriteLine(test.Replace("http://", "http://www."));
    }
    

    【讨论】:

    • 正则表达式似乎不正确 [^www.] 匹配 不是 w单个 字符>.(点)。用http://willywonka.com 试试你的正则表达式。
    【解决方案8】:

    您不需要 RegEx,只需简单的替换即可:

    var temp = new string[] {"http://google.com", "http://www.google.com", "http://gmail.com", "https://www.gmail.com", "https://example.com"};
    
    var urlWithoutWWW = temp.Where(d => 
                             d.IndexOf("http://www") == -1 && d.IndexOf("https://www") == -1);
    
    foreach (var newurl in urlWithoutWWW)
    {
         Console.WriteLine(newurl.Replace("://", "://www."));
    }
    

    【讨论】:

    • 我需要使用正则表达式,因为这是在 ASP.NET Core 方法中使用的。
    • 所以,这个可以在.net core中使用。
    【解决方案9】:

    现在最常见的情况是,您希望同时重定向到 www 和 https。 hankors 的回答很好,但需要两个重定向而不是一个,所以我重写了他的自定义规则,以便在需要时添加 www 和 https。结果只是一个重定向(如果您在 Azure 中打开 https 重定向)。

        public class RedirectToHttpsWwwRule : IRule
    {
        public void ApplyRule(RewriteContext context)
        {
            var req = context.HttpContext.Request;
            if (req.Host.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase))
            {
                context.Result = RuleResult.ContinueRules;
                return;
            }
            HostString wwwHost;
    
            if (req.IsHttps)
            {
                if (req.Host.Value.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
                {
                    context.Result = RuleResult.ContinueRules;
                    return;
                }
                else
                {
                    wwwHost = new HostString($"www.{req.Host.Value}");
                }
            }
            else
            {
                if (req.Host.Value.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
                {
                    wwwHost = new HostString(req.Host.Value);
                }
                else
                {
                    wwwHost = new HostString($"www.{req.Host.Value}");
                }
            }
    
            string newUrl = UriHelper.BuildAbsolute("https", wwwHost, req.PathBase, req.Path, req.QueryString);
            var response = context.HttpContext.Response;
            response.StatusCode = 301;
            response.Headers[HeaderNames.Location] = newUrl;
            context.Result = RuleResult.EndResponse;
        }
    }
    

    【讨论】:

      【解决方案10】:

      我也在 .net 6 ASP.net 应用程序中使用了 SuperDuck 的答案。我的代码是:

      using Microsoft.AspNetCore.Rewrite;
      
      app.UseRewriter(new RewriteOptions().AddRedirectToWwwPermanent().AddRedirectToHttpsPermanent()); // in program.cs
      

      它重定向到 www 子域以及 web-app 的 https 版本。

      【讨论】:

      • 这并不能真正回答问题。如果您有其他问题,可以点击 提问。要在此问题有新答案时收到通知,您可以follow this question。一旦你有足够的reputation,你也可以add a bounty 来引起对这个问题的更多关注。 - From Review
      猜你喜欢
      • 2018-06-06
      • 1970-01-01
      • 2011-01-05
      • 2012-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多