如何从URL中去除.html后缀?

184

如何从静态页面的URL中删除.html?

此外,我需要将任何带有.html的URL重定向到没有.html的URL(例如,将www.example.com/page.html重定向到www.example.com/page)。


2
“去掉 .html” 是指 “不需要存在 .html 吗?” - Lightness Races in Orbit
@Tomalak:是的,还要将带“.html”扩展名的重定向到不带扩展名的。我的问题是这会导致无限重定向。我的当前设置允许同时访问www.example.com/page.html和www.example.com/page,这对SEO并不友好。 - Dave
3
请参考以下链接:https://dev59.com/mFXTa4cB1Zd3GeqP6vge、https://dev59.com/3FXTa4cB1Zd3GeqP6ffd 和 http://stackoverflow.com/questions/5639367/mod-rewrite-recursive-loop。这些链接讨论了关于请求循环的原因、PHP中.htaccess文件实现美化URL的反向操作,以及mod_rewrite递归循环的问题。 - Lightness Races in Orbit
@Tomalak:感谢你的建议。阅读mod_rewrite的文档非常有帮助。 - Dave
另外请参考这个“如何移除HTML和PHP”的教程:https://helponnet.com/2020/02/04/remove-html-and-php-extension-with-htaccess-rewriterule-url-rewriting-tips/ - Amit Verma
18个回答

154
要从您的URL中删除.html扩展名,您可以在根目录/htaccess中使用以下代码:
RewriteEngine on


RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
RewriteRule ^ /%1 [NC,L,R]

RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [NC,L]

注意:如果你想移除其他扩展名,例如移除.php扩展名,只需在上述代码中将html替换为php
另外,请参考这个如何使用htaccess从URL中移除.html和.php

17
其他回答对我没用,但是这个有效了,非常感谢! - Emmet Arries
2
这个也对我有用。谢谢@starkeen。给你一个^赞。 - JeremyS
3
运作得非常好。谢谢! - ixany
1
从许多网站、手册和文档中,这个解决方案是拯救我的。非常感谢。 - DrBeco
@DrBeco 没问题,很高兴能帮到你。如果你想学习URL重写的基础知识,可以关注我的博客“HelpOnNet”,或者从我的SO个人资料中购买教程。 - Amit Verma
显示剩余2条评论

145

我认为对Jon的回答进行一些解释会更有建设性。以下是:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

检查指定的文件或目录是否不存在,如果不存在,则继续执行重写规则。
RewriteRule ^(.*)\.html$ /$1 [L,R=301]

但这意味着什么?它使用正则表达式。这是我之前做的一点东西...enter image description here

认为那是正确的。

注意:在测试你的.htaccess时,不要使用301重定向。在完成测试之前,请使用302,因为浏览器会缓存301。请参见https://dev59.com/t2ox5IYBdhLWcg3whUmm#9204355

更新:我稍微错了,.匹配除换行符外的所有字符,因此包括空格。另外,这里有一个有用的正则表达式速查表

来源:

http://community.sitepoint.com/t/what-does-this-mean-rewritecond-request-filename-f-d/2034/2

https://mediatemple.net/community/products/dv/204643270/using-htaccess-rewrite-rules


20
超棒的图表能够帮助解释答案。 - Ric
301重定向和浏览器缓存的提示解决了我的问题。 - bgfvdu3w
@KnocksX 我不再是网站管理员,也没有能力提供帮助。 - binaryfunt
2
图形不错,但与其引用的答案一样,这个答案误解了实际问题,并假设所有文件都没有使用“.html”扩展名保存。请参见我的答案以获得更详细的解释。 - Kal
对我不起作用。我该如何调试它? - Black
尝试Lukasz的答案:https://dev59.com/aW025IYBdhLWcg3w6KSO#11813084,我认为它对我有帮助。 - binaryfunt

81
这对你应该有效:

这应该对你有用:

#example.com/page will display the contents of example.com/page.html
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.+)$ $1.html [L,QSA]

#301 from example.com/page.html to example.com/page
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*\.html\ HTTP/
RewriteRule ^(.*)\.html$ /$1 [R=301,L]

4
我在Godaddy上的这段代码出现了404错误,我通过将"Options +FollowSymLinks -MultiViews -Indexes"放在最顶部进行修复。 - Labanino
1
我认为这是最好、最完整的答案,谢谢! - Arian
我尝试在本地主机上做这件事,但它没有正常工作,我需要做其他的事情吗?我需要链接 .htaccess 文件吗?或者页面是如何识别它的? - Pianistprogrammer
如何将 example.com/page.html 的 #301 重定向添加 .php 扩展名,变成 example.com/page.php ,这是否可行? - user10202925
这对我在GoDaddy上也起作用了(无需添加@Labanino所述的代码)。 - Supertecnoboff

76

使用Apache下的.htaccess文件可以实现重定向,代码如下:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\.html$ /$1 [L,R=301] 

如果要从URL中删除“.html”,只需链接到没有“.html”扩展名的页面即可。

<a href="http://www.example.com/page">page</a>

29
这对我没有任何作用。有什么原因它不能工作吗? - Michael Yaworski
您是否有所请求链接的实际文件?这将触发 !-f - Martijn
1
@Martijn,我认为这就是重点——你在/page.html有一个文件,但你想用/page链接到它。我怀疑这个答案误解了问题,并假设OP没有保存他的页面时没有使用.html扩展名(据我所读,这并不是情况)。 - Kal

29

你需要确保你也有 Options -MultiViews

以上方法在标准的 cPanel 主机上对我都没有起作用。

这个方法有效:

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]

在所有上面的答案中,这个最终起作用了。我相信是因为我的网站托管在带有cPanel的godaddy上。关键是选项-MultiViews。 - Brad Vanderbush
是的,在这个部分里除了这个答案,其他什么都不起作用!你救了我的一天! - Nobody
谢谢,伙计。我不确定为什么其他的没有达到预期的效果。 - Nanoo
我该如何在URL末尾添加斜杠?site.com/test可以正常工作,但site.com/test/不行...编辑:看起来RewriteRule ^([^.]+)/$ $1.html [NC,L]可以解决问题。这样可以吗? - Andrei

24

如果你正在使用 Firebase Hosting,那么这个页面上的所有答案都行不通。因为 Firebase Hosting 不支持使用 .htaccess 文件。你需要配置 firebase.json 文件。只需在文件中添加一行代码 "cleanUrls": true 并保存即可。

添加该代码后,firebase.json 会变成这样:

{
  "hosting": {
    "public": "public",
    "cleanUrls": true, 
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ]
  }
}

+1. 我想知道是否有类似的方法可以用于GitHub页面,因为似乎最受欢迎的答案如果您将网站托管在GitHub Pages(gh-pages)上,则无法正常工作 - Nike

15

感谢您的回复。我已经解决了我的问题。假设我的页面在http://www.yoursite.com/html下,以下.htaccess规则适用。

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /html/(.*).html\ HTTP/
   RewriteRule .* http://localhost/html/%1 [R=301,L]

   RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /html/(.*)\ HTTP/
   RewriteRule .* %1.html [L]
</IfModule>

13

好问题,但似乎让人有些困惑。答案几乎被分为两部分,一部分认为Dave(原帖作者)在保存HTML页面时没有使用.html 扩展名,另一部分则认为他保存了正常的HTML文件(包括.html),但希望URL不显示它。虽然这个问题可能可以措辞得更好,但我认为他的意思很清楚。如果他在保存页面时没有使用.html,那么他的两个问题(“如何删除.html”)和(“如何重定向任何带.html的URL”)将是完全相同的问题!因此,那种解释并没有太多意义。此外,他的第一个评论(关于避免无限循环)和他自己的答案似乎证实了这一点。

所以让我们重新表述这个问题并分解任务。我们想要完成两件事:

  1. 如果.html是请求的URL的一部分(例如/page.html),则可见地删除它。
  2. 将修剪后的URL(例如/page)指回实际的文件(/page.html)。

做这两件事情都不难。(我们只需通过启用MultiViews来实现第二件事情。)这里的挑战是在不创建无限循环的情况下同时完成它们两个。

Dave的答案解决了问题,但相当复杂且不太可移植。(抱歉Dave。)Łukasz Habrzyk似乎整理了Anmol的答案,最后Amit Verma改进了它们两个。然而,他们都没有解释他们的解决方案如何解决根本问题——如何避免无限循环。据我所知,它们之所以有效是因为THE_REQUEST变量保存了浏览器发出的原始请求。因此,条件(RewriteCond %{THE_REQUEST})只会被触发一次。由于它不会在重写时被触发,所以避免了无限循环的情况。但是你要处理完整的HTTP请求-GET,HTTP等-这在某种程度上解释了这个页面上一些难看的正则表达式示例。

我将提供另一种方法,我认为它更容易理解。我希望这有助于未来的读者理解他们正在使用的代码,而不仅是复制并粘贴他们几乎不理解但希望一切顺利的代码。

RewriteEngine on

# Remove .html (or htm) from visible URL (permanent redirect)
RewriteCond %{REQUEST_URI} ^/(.+)\.html?$ [nocase]
RewriteRule ^ /%1 [L,R=301]

# Quietly point back to the HTML file (temporary/undefined redirect):
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [END]

让我们来分解一下...

第一个规则很简单。该条件匹配任何URL以.html(或.htm)结尾,并重定向到没有文件名扩展名的URL。这是一个永久性重定向,表示被裁剪的URL是规范化的URL。

第二个规则也很简单。如果所请求的文件名不是有效目录(!-d),那么第一个条件只会通过。第二个条件只有在文件名引用带有.html扩展名的有效文件(-f)时才会通过。如果两个条件都通过了,那么重写规则只是将“.html”添加到文件名中。然后魔法发生了...[END]。是的,这就足以防止无限循环。Apache的RewriteRule Flags documentation对此进行了解释:

使用[END]标志不仅终止当前重写轮次(类似于[L]),而且还防止在每个目录(htaccess)上下文中发生任何后续的重写处理。


1
这个效果非常好。谢谢你的解释。 - Fahim Foysal
1
这个效果非常好。还有,谢谢你的解释。 - undefined

10

使用.htaccess 对静态 HTML 重写 URL 不仅不必要,而且会对您的网站性能产生负面影响。启用 .htaccess 也是一种不必要的安全漏洞 - 关闭它可以消除大量潜在问题。每个 .htaccess 文件的相同规则可以放入该目录的 <Directory> 部分,如果然后设置 AllowOverride None,将更加高效,因为它不需要检查每个目录是否有 .htaccess 文件,更加安全,因为攻击者无法在没有 root 访问权限的情况下更改虚拟主机配置。

如果在 VPS 环境中不需要 .htaccess,可以完全禁用它,并从您的 Web 服务器获取更好的性能。

您只需要将单独的文件从以下结构移动:

index.html
about.html
products.html
terms.html

对于这样的结构:

index.html
about/index.html
products/index.html
terms/index.html

你的 Web 服务器将呈现相应的页面 - 如果你加载 /about/,它会将其视为 /about/index.html

然而,如果有人访问旧的网址,这样不会重写 URL,所以如果要对现有网站进行追溯应用,则需要设置重定向。


如果您正在管理VPS,为什么不将重写添加到Apache配置文件(httpd.conf)中,而不是.htaccess文件中呢?如果您不是管理员,那么当然会受到一些性能影响。我想您需要权衡一下这一点,看看是否值得为您的网站上的每个文件创建一个目录。 - Kal
而且您不需要为网站上的每个文件创建一个目录 - 最多只需将所有规则移动到vhost配置中的<Directory>指令中即可。 - Matthew Daly
这是一个非常好的观点和聪明的解决方案。 - CristianMoisei
我在本地 URL 中仍然看到“.html”扩展名,这正常吗?它会在服务器上消失吗? - Farid Mammadaliyev
1
只要您使用Web服务器运行它,而不仅仅是在本地文件夹中导航文件,那么是的 - 这是Web服务器提供文件的方式之一,它默认为“index.html”。链接或加载“/about/index.html”将起作用,但“/about/”也将起作用,因此您的内部链接需要指向文件夹,而不是文件。 - Matthew Daly
显示剩余4条评论

8

我使用以下 .htaccess 文件来删除我的网站 URL 中的 .html 扩展名,请帮忙验证是否正确:

    RewriteEngine on
RewriteBase /
RewriteCond %{http://www.proofers.co.uk/new} !(\.[^./]+)$
RewriteCond %{REQUEST_fileNAME} !-d
RewriteCond %{REQUEST_fileNAME} !-f
RewriteRule (.*) /$1.html [L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^.]+)\.html\ HTTP
RewriteRule ^([^.]+)\.html$ http://www.proofers.co.uk/new/$1 [R=301,L]

这对我很有效,不像其他在这里提出的解决方案,谢谢。但是我想补充一点,你仍然需要更新HTML中的链接(所以如果你最初将你的.html文件链接为<a href="page1.html"></a>,你应该将其更新为<a href="http://www.example.com/page1"></a>,然后它就会起作用)。 - Lorenzo
对我来说最核心的更改是 RewriteBase / 部分。不幸的是,我不明白为什么它起作用,但我想我很快就会学到了。 - Keno

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