Redirect Non WWW to WWW using Asp.Net Core Middlew

2019-02-16 09:53发布

问题:

On an ASP.Net Core application startup I have:

RewriteOptions rewriteOptions = new RewriteOptions(); 

rewriteOptions.AddRedirectToHttps();

applicationBuilder.UseRewriter(rewriteOptions);

When in Production I need to redirect all Non WWW to WWW Urls

For example:

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

How can I do this using Rewrite Middleware?

I think this can be done using AddRedirect and Regex:

Github - ASP.NET Core Redirect Docs

But not sure how to do it ...

回答1:

A reusable alternative would be to create a custom rewrite rule and a corresponsing extension method to add the rule to the rewrite options. This would be very similar to how AddRedirectToHttps works.

Custom Rule:

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;
    }
}

Extension Method:

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

Usage:

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

Future versions of the rewrite middleware will contain the rule and the corresponding extension method. See this pull request



回答2:

I'm more of an Apache user and fortunately URL Rewriting Middleware in ASP.NET Core provides a method called AddApacheModRewrite to perform mod_rewrite rules on the fly.

1- Create a .txt file whatever the name and put these two lines into it:

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

2- then call it this way:

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

Done!



回答3:

Using just a regex,

Find ^(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,})))

Replace $1www.$2

Expanded

 ^                             # 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)


回答4:

It's unclear from if what AddRedirect method does and if it actually accepts regex.

But to insert a "www" to a url without "www"?
You could try it with these strings:

string pattern = @"^(https?://)(?!www[.])(.*)$";
string replacement = "$1www.$2";

//Regex rgx = new Regex(pattern);
//string redirectUrl = rgx.Replace(url, replacement);

Because of the negative lookahead (?!www[.]) after the protocol, it'll ignore strings like http://www.what.ever

$1 and $2 are the first and second capture groups.



回答5:

I think instead of using Regex unless it is a must you can use the Uri class to reconstruct your url

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}";

And the result will look like

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


回答6:

Here's a regex to try:

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

It will select URLs like:

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

But not like:

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

I prefer to use explicit extensions (e.g. .com, .gov, or .org) when possible, but you could also use something like this if it is beneficial to your use case:

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

I would then approach the replacement with something like the following:

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."));
}


回答7:

You don't need a RegEx, just a simple replace will work:

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."));
}