Apache将非www重定向到www

236

我有一个网站似乎没有从非www重定向到www。

我的Apache配置如下:

RewriteEngine On
### re-direct to www
RewriteCond %{http_host} !^www.example.com [nc]
RewriteRule ^(.*)$ http://www.example.com/$1 [r=301,nc] 

我漏掉了什么?


1
对于基于.htaccess的解决方案,我建议参考在相反问题上提出的答案:https://dev59.com/YHVC5IYBdhLWcg3woCnN#5262044 - hakre
这很好,但它确实在URL中添加了一个斜杠,所以在美元符号之前去掉斜杠。 - wuxmedia
可能是通用htaccess重定向www到非www的重复问题。 - Bobík
26个回答

562

使用重写引擎解决此问题是一种相对复杂的方法。这里有一个更简单的解决方案:

<VirtualHost *:80>
    ServerName example.com
    Redirect permanent / http://www.example.com/
</VirtualHost>

<VirtualHost *:80>
    ServerName www.example.com
    # real server configuration
</VirtualHost>

然后您将拥有另一个<VirtualHost>部分,其中包含ServerName www.example.com以供您的真实服务器配置。当使用Redirect指令时,Apache会自动保留斜杠/之后的任何内容,这是关于为什么此方法不起作用的常见误解(实际上它确实有效)。


26
如果一个网站有 SSL 虚拟主机,你该如何处理呢? - Shabbyrobe
29
当我使用这个建议时,会出现“example.com的网页导致了太多重定向”的错误。其他人也有这个问题吗? - Jonathan Berger
4
在进行反向操作时,并没有什么神奇的地方。只需在示例中出现的位置上交换 www.exampleexample 即可。 - Greg Hewgill
11
如果您有太多的重定向,则可能没有正确配置文件。确保有两个VirtualHosts:一个是非www的,即上面提到的,另一个是具有实际配置的ServerName www.example.com。还要确保在www.example.com的配置中,没有重定向(无论是mod_alias还是mod_rewrite都不行)。 - Savas Vedova
3
对于一个虚拟主机服务器,比如example.com,我有这样一条指令:Redirect 301 / http://example2.com/extra/ 但是当它进行重定向时,会丢失尾随的斜线,这意味着example.com/blah会被重定向到example2.com/extrablah。有什么解决方法吗?(Apache 2.2.22) - Peter Howe
显示剩余23条评论

114

http://example.com/subdir/?lold=13666 => http://www.example.com/subdir/?lold=13666

这段代码是将一个URL地址中的“example.com”替换成“www.example.com”。
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

4
太好了,这可以在服务器配置的顶层进行设置(如果可以的话),并且将适用于每个虚拟主机! - thenickdude
你好 @burzumko,您如何实现对于所有无 www 的情况下,让 example.com/subdi1/ws/*通过,但其他情况不通过呢? - black sensei
2
我也用这个解决方案来处理HTTPS虚拟主机。只需在第三行的http后面添加s即可。 - rodrigoap

56
<VirtualHost *:80>
    ServerAlias example.com
    RedirectMatch permanent ^/(.*) http://www.example.com/$1
</VirtualHost>

这对我没有用,它导致了一个无限的重定向循环到同一个网站。 - dmiller309
2
@dmiller309:你是否在ServerAlias中包含了www. - cherouvim
2
你说得对,我在ServerAlias中使用了*.通配符的www。是我的VirtualHost条目顺序搞错了,导致*.通配符有机会匹配,而我并没有想到这一点。 - dmiller309
8
这是最佳答案,因为它干净整洁,保留了路径(不像第一个答案),并且没有使用重写。 - schieferstapel

35

要从您的URL网址中移除www,请在您的.htaccess文件中使用以下代码:

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

如果想在网站的URL中强制添加www,请在.htaccess文件中使用以下代码:

RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^YourSite.com$
RewriteRule ^(.*)$ http://www.yourSite.com/$1 [R=301]
RewriteCond %{REQUEST_fileNAME} !-d
RewriteCond %{REQUEST_fileNAME} !-f
RewriteRule ^(([^/]+/)*[^./]+)$ /$1.html [R=301,L]

在编程中,YourSite.com 必须替换为您的 URL


1
最佳答案在这里,因为它适用于具有多个域名的网站 <3 - Clement Herreman
2
第二部分的 .html 是用来做什么的? - Nathan H
7
将$1前面的斜杠移除,以避免重定向后出现双斜杠(//) => RewriteRule ^(.*)$ http://www.yourSite.com$1 [R=301] - Kevin Campion

25
    <VirtualHost *:80>
       DocumentRoot "what/ever/root/to/source"
       ServerName www.example.com

       <Directory "what/ever/root/to/source">
         Options FollowSymLinks MultiViews Includes ExecCGI
         AllowOverride All
         Order allow,deny
         allow from all
         <What Ever Rules You Need.>
      </Directory>

    </VirtualHost>

    <VirtualHost *:80>
      ServerName example.com
      ServerAlias *.example.com
      Redirect permanent / http://www.example.com/
    </VirtualHost>

以上代码的作用如下。第一个虚拟主机块检查请求是否为www.example.com,并在该目录中运行您的网站。

如果不成功,则转到第二个虚拟主机部分。在这里,任何不是www.example.com的请求都将重定向到www.example.com。

这里的顺序很重要。如果先添加第二个virtualhost指令,它会导致重定向循环。

此解决方案将重定向任何请求到您的域,至www.yourdomain.com。

干杯!


19

既可以将非www => www,也可以将相反的www =>非www进行重定向。不要在.htaccess文件中硬编码域名和协议。因此,原始域名和http / https版本将被保留。

APACHE 2.4及更高版本

NON-WWW => WWW:

RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ %{REQUEST_SCHEME}://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

WWW => 非WWW:

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

注意:在 Apache 2.2 上不起作用,因为 %{REQUEST_SCHEME} 不可用。若要与 Apache 2.2 兼容,请使用以下代码或将 %{REQUEST_SCHEME} 替换为固定的 http/https。


Apache 2.2 及以上版本

非 WWW => WWW:

RewriteEngine On

RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

RewriteCond %{HTTPS} on
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

... 或简短版本...

RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTPS}s ^on(s)|offs
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

将WWW转化为非WWW:

RewriteEngine On

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

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

...无法提供更短的版本,因为%N仅从最后一个RewriteCond可用...


Apache 2.4配置修复了问题,感谢干净的答案..!! - KimchiMan

16

这与许多其他建议类似,但有一些改进:

  • 无需硬编码域名(适用于接受多个域名或在不同环境之间工作的虚拟主机)
  • 保留方案(http/https)并忽略先前%{REQUEST_URI}规则的影响。
  • 路径部分不受先前RewriteRule(如%{REQUEST_URI})的影响。

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

4
几乎完美。它必须是 %{HTTP_HOST}$1,而不是 %{HTTP_HOST}/$1(否则它会导致斜杠重复)。 - Michael Wyraz
@Michael Wyraz:这里不需要双斜杠吗?! - not2savvy

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

这段代码以HTTP_HOST变量开头,其中包含传入URL的域名部分(example.com)。假设域名不包含www.并且与您的域名完全匹配,则RewriteRule开始发挥作用。模式^(.*)$将匹配REQUEST_URI中的所有内容,这是HTTP请求中请求的资源(foo/blah/index.html)。它将此存储在后向引用中,然后使用新域名(以www开头的域名)重写URL。

[NC]表示不区分大小写的模式匹配,[R=301]表示使用代码301进行外部重定向(资源永久移动),[L]停止所有进一步的重写,并立即重定向。


10

如果您正在使用Apache 2.4,无需启用rewrite Apache模块,您可以使用类似以下方式的方法:

# non-www to www
<If "%{HTTP_HOST} = 'domain.com'">
  Redirect 301 "/" "http://www.domain.com/"
</If>

3
被低估的答案。使用这个方法,可以避免额外的虚拟主机,这对于自动化的Let'sEncrypt脚本非常有好处。 - Paul
此外,如果您正在使用ANSIBLE,自从ANSIBLE 2.0以来,您现在可以轻松地在一个任务中将一个块插入到文件中,更多详细信息请参见https://docs.ansible.com/ansible/2.5/modules/blockinfile_module.html。 - sys0dm1n

5

我运行了这个...

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

我需要这个在我们新服务器上的25个以上域名都通用,所以这个指令在我的virtual.conf文件中的标签中。(dir是所有文档根目录的父目录)
我必须对重写规则进行一些修改,因为尽管http://httpd.apache.org/docs/2.2/mod/mod_rewrite.html中说只有主机和端口之后的内容才会被匹配,但完整的文档根目录仍然通过模式匹配传递。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接