代码之家  ›  专栏  ›  技术社区  ›  user3422533

htaccess:防止301重定向将/附加到子文件夹的URL末尾

  •  1
  • user3422533  · 技术社区  · 2 年前

    我定义了这个 .htaccess 文件:

    RewriteEngine On
    
    # Disable http
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    
    # Disable www.
    RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
    RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
    
    # /random run random.php
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME}\.php -f
    RewriteRule ^([^\.]+)$ $1.php [NC,L]
    
    # Redirect /index.html in URL to /
    RewriteRule (.*)index\.html$ /$1 [R=301,L]
    
    # Redirect xxx.html in URL to nach xxx
    RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
    RewriteRule ^ /%1 [NC,L,R]
    
    RewriteCond %{REQUEST_FILENAME}.html -f
    RewriteRule ^ %{REQUEST_URI}.html [NC,L]
    

    我有这样的文件夹结构:

      • index.html
      • about.html
      • example (目录)
        • index.html
        • x.html

    它适用于:

    • 主页是 x.com
    • x.com/about 返回的文件内容 /about.html
    • x.com/about.html 重定向到 x.com/关于
    • x.com/example/x 返回的文件内容 /example/x.html
    • x.com/example/ 返回的文件内容 /example/index.html

    但这种情况也会发生,我想不允许这样做:

    • x.com/example 重定向到 x.com/example/
    • x.com/example 应返回的文件内容 /example/index.html

    你知道我的 .htaccess 文件

    1 回复  |  直到 2 年前
        1
  •  1
  •   MrWhite    2 年前

    x.com/example 重定向到 x.com/example/

    自从 /example 是一个物理目录,mod_dir“修复”了URL,并在后面的斜杠中添加301(永久)重定向。尾部斜线为 必修的 以便服务器 DirectoryIndex (即。 index.html 在这种情况下)。

    但是,我们可以防止mod_dir在尾部斜杠后面附加 DirectorySlash Off 指令。但是,我们必须发布一个内部重写来附加尾部斜杠,否则 目录索引 文件将不会送达(如上所述)。(或者,我们可以直接重写到索引文档。)

    设置时 DirectorySlash关闭 我们还必须确保禁用目录列表(modautoindex),因为该目录中存在索引文档将不再阻止目录列表。

    为了解决潜在的规范化问题,您现在需要向另一个方向“重定向”,以删除请求的URL上的任何尾部斜杠。例如请求 /example/ 现在需要重定向回 /示例 .

    此外,以下规则重写到相应的 .html 文件不完全正确:

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

    这个 条件 (使用 REQUEST_FILENAME )不一定要测试您最终要在中重写到的相同URL 替代 (使用 REQUEST_URI ).因此,在某些情况下(例如,当请求目录中不存在的文件时,该文件恰好也映射到 .html 文件),您可以得到一个重写循环(500内部服务器错误)。请参阅以下关于ServerFault的问题/答案,该问题/答案将对此进行详细介绍: https://serverfault.com/questions/989333/using-apache-rewrite-rules-in-htaccess-to-remove-html-causing-a-500-error

    这同样适用于早期的规则,该规则将 .php 扩大

    综合以上几点,我们得出以下结论:

    # [NEW] Directory listing (mod_autoindex) must be disabled
    Options -Indexes
    
    # [NEW] Prevent mod_dir appending the trailing slash
    DirectorySlash Off
    
    RewriteEngine On
    
    # Disable http
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    
    # Disable www.
    RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
    RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
    
    # Redirect /index.html in URL to /
    RewriteRule (.*)index\.html$ /$1 [R=301,L]
    
    # Redirect xxx.html in URL to just xxx
    RewriteCond %{THE_REQUEST} /([^.?]+)\.html [NC]
    RewriteRule ^ /%1 [R=301,L]
    
    # [NEW] Redirect to remove trailing slash on direct requests
    RewriteCond %{ENV:REDIRECT_STATUS} ^$
    RewriteRule (.+)/$ /$1 [R=301,L]
    
    # [NEW] Internal rewrite to append trailing slash to directories
    RewriteCond %{DOCUMENT_ROOT}/$1 -d
    RewriteRule (.+) $1/ [L]
    
    # /random run random.php
    RewriteCond %{DOCUMENT_ROOT}/$1.php -f
    RewriteRule ^([^\.]+)$ $1.php [L]
    
    # Append ".html" if corresponding file exists
    RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f
    RewriteRule ^ %{REQUEST_URI}.html [L]
    

    与您的即时问题相关的新规则用表示 [NEW] .

    在测试之前,您需要清除浏览器缓存,因为附加了尾部斜杠的301(永久)重定向将被缓存。使用302(临时)重定向进行测试,以避免潜在的缓存问题。

    附加说明:

    • 在测试同一个请求加上 .php 映射到文件,这些都是互斥的事件,特别是因为 RewriteRule 图案 排除点(所以排除具有文件扩展名的URL),所以我删除了 条件 .

    • 无需在中反斜杠转义文字点 RewriteCond 测试字符串 因为这是一个“普通”字符串,而不是正则表达式。

    • 不需要 NC 的两个上的旗帜 重写规则 指令,因为regex已经匹配a-z和a-z。

    • 我对规范重定向进行了分组 之前 内部重写。

    # Redirect xxx.html in URL to nach xxx
    RewriteCond %{THE_REQUEST} /([^.]+)\.html [NC]
    RewriteRule ^ /%1 [NC,L,R]
    

    请注意,我还在中修改了regex 条件 以避免匹配潜在的查询字符串,否则为表单的请求 /foo.html?bar.html 将导致双重重定向,并且查询字符串将损坏。

    注意:您目前没有相应的规则 .php 请求。(您可以在同一规则中处理这两个问题。)

    推荐文章