Apache .htaccess-如果文件不存在,则重定向到父目录

Apache .htaccess-如果文件不存在,则重定向到父目录,apache,.htaccess,Apache,.htaccess,我的网站上有些页面有amp版本,但有些页面只有普通版本。一般来说,结构如下所示: \ \page1.htm \page2.htm ... \amp\ \amp\page1.htm 所以page1.htm有它的amp版本,但是page2.htm-没有。 当用户检索\amp\page2.htm而不是404时,我希望从根目录提供page2.htm 我已尝试通过.htaccess进行重定向,但无法正常工作: RewriteCond %{REQUEST_URI} ^/amp/ RewriteCond %

我的网站上有些页面有amp版本,但有些页面只有普通版本。一般来说,结构如下所示:

\
\page1.htm
\page2.htm
...
\amp\
\amp\page1.htm
所以page1.htm有它的amp版本,但是
page2.htm
-没有。 当用户检索
\amp\page2.htm
而不是404时,我希望从根目录提供
page2.htm

我已尝试通过.htaccess进行重定向,但无法正常工作:

RewriteCond %{REQUEST_URI} ^/amp/
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteRule ^/amp/(.*)$ https://www.example.com/$1 [R=301,L]
这个代码有什么问题?为什么我还拿到404


谢谢

这是一个棘手的问题,突出了mod_重写的微妙之处。简而言之,有两种方法可以做到这一点:

RewriteCond %{REQUEST_URI} ^/amp/(.*)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . https://www.example.com/%1 [R=301,L]
几个重要的区别:

  • 我在RewriteCond而不是RewriteRule中捕获请求URI的尾部,然后使用%1(
    %1
    )而不是美元1(
    $1
    )引用它
  • 我使用REQUEST\u FILENAME来查看文件系统上是否存在文件,而不是DOCUMENT\u ROOT/REQUEST\u URI,因为REQUEST\u URI可以是任何内容,并且可能与文件系统上的内容一致,也可能不一致(如您的示例所示)
  • RewriteRule
    匹配所有内容(与
    不同的是
    /amp/
  • 或者你可以:

    RewriteBase /amp
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^amp(.*)$ $1 [R=301,L]
    
    这两种不同方法的工作原理与官方mod_rewrite文档中的这句话有关(重点是我的):

    请注意,mod_rewrite通过检查路径的第一段是否存在于文件系统的根目录中,尝试猜测您是否指定了文件系统路径或URL路径。例如,如果指定替换字符串/www/file.html,则该字符串将被视为URL路径,除非根目录或文件系统中存在名为www的目录(或者,如果在.htaccess文件中使用相对于文档根的重写),在这种情况下,该目录将被视为文件系统路径

    第一种方法将对象视为URL路径,而第二种方法将对象视为文件路径

    我想第一种方法更符合您的需要,因为amp解决方案通常是“生成的”(并且不是文件系统中的平面文件),因此,您更感兴趣的是将输入作为URL路径而不是文件路径来使用

    在你想“哇!人们怎么能把这些东西留在脑子里?”。我对mod_重写规则只有模糊的理解,实际上在写这篇文章之前,我不得不重新阅读文档并运行一些测试来澄清问题

    希望这有帮助

    一些供参考的URL: