使用 Asp.Net Core 中间件将非 WWW 重定向到 WWW

Posted

技术标签:

【中文标题】使用 Asp.Net Core 中间件将非 WWW 重定向到 WWW【英文标题】:Redirect Non WWW to WWW using Asp.Net Core Middleware 【发布时间】: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 在这种情况下有效吗? 【参考方案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

以上是关于使用 Asp.Net Core 中间件将非 WWW 重定向到 WWW的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core 2.1 中的 HttpClientFactory (Part 3) 使用Handler实现传出请求中间件

如何将非 www 域重定向到 Azure 上托管的 asp.net mvc 中的 WWW 域?

asp.net core中托管SPA应用

如何在 ASP.Net Core 中使用 条件中间件

ASP.Net Core 异常处理中间件

ASP.NET Core 中间件基本用法