如何RewriteRule而不破坏源文件的相对路径加载?

如何RewriteRule而不破坏源文件的相对路径加载?

我在服务器上有一个丑陋的文件系统路径:example.com/a/b/c/d/e/f/main.html。为简单起见,我将example.com/httpdocs/main.html在本问题正文中使用它。

我希望用户看到的是。我将在这个问题中example.com/easy-to-remember使用。example.com/abc

由于超出问题范围的原因,我只想使用文件.htaccess而不是 php-routing 来执行此操作。

让我们从可行的案例开始:

RewriteEngine On

# Rewrite abc/ directory for loading of source material
    # Rewrite only if there is no actual file or directory that matches this request
    #   This can especially be useful for loading resources  
    #   because then the full paths won't be redirected if they are correct.
    # Note that RewriteRule never sees leading slashes
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^abc/(.*)$ httpdocs/$1 [NC,L]

这样,用户可以打开example.com/abc/main.html(expressive path)并显示内部存储在example.com/httpdocs/main.html(ugly path)的页面。用户永远不会看到内部路径;url 仍保留/abc/main.html在他们的浏览器中。

到目前为止,一切都按预期运行。在 中以相对路径指定的 CSS 源文件main.html仍可正确加载。
但可能main.html是一个非常无用的名称。我宁愿使用example.com/abc而不是example.com/abc/main.html。这样会更具表现力,并允许在不更改链接的情况下对文件扩展名进行内部更改。

# Rewrite abc without trailing slash to main.html
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^abc$ httpdocs/main.html
    # PROBLEM: This turns the current url into "example.com/abc", so "./libs"
    # is now looked for in "example.com/libs" instead of "example.com/httpdocs/libs"  

此规则仍然适用于加载main.html但不向用户在 URL 中显示该名称。
但现在相对路径解析错误

/httpdocs/main.html依赖于/httpdocs/libs/source.css。在第一种情况下,我们访问/abc/main.html,源从 加载/abc/libs/source.css,并且这些加载被重定向到 ,/httpdocs/libs/source.css因此一切正常。在第二种情况下,我们访问/abc,css 从 加载/libs/source.css,省略了/httpdocs目录 - 这会导致 404,因此页面现在不再正确呈现(以这种方式访问​​时)。

显而易见的解决方案是保留第一种情况,如果我真的不想向main.html用户显示名称,我可以另外添加一条重定向/abc/expressive-name/abc/main.html(或直接到/httpdocs/main.html) 的规则。
但我很好奇是否有办法实现我想要做的事情,而无需在 URL 中添加第二个深度级别 (另一个斜线)。

我想保持源的相对加载,这样如果我必须将整个文件系统移动到另一个子域,我只需将整个内容复制过来即可。如果没有这个限制,我只需将所有加载都设置为绝对加载即可。

答案1

正如您所发现的,您必须将主文件的 URL 保持在同一级别,以使相对链接起作用。一种简单的方法是使用 URL/abc/而不是/abc

区别在于浏览器将什么视为当前目录或基本 URL。基本 URL 是删除最后一个 之后所有内容的 URL /。因此,/abc基本 URL 为 ,//abc/基本 URL 为/abc

因此你可以写:

RewriteRule ^abc/$ httpdocs/main.html

或者你可以省略 URL 中的文件名(如果你提供

#RewriteCond %{REQUEST_FILENAME} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^abc(.*)$ httpdocs$1
DirectoryIndex main.html

RewriteCond 规则只是为了确保目标不是现有的文件或目录。当您知道目标不存在时,您可以省略规则。

如果您的主文件始终命名为 main.html,则您可以DirectoryIndex只将其添加到根目录(或共同祖先)。这将使 RewriteRules 更短,因为您不需要为目录和主文件分别设置 RewriteRules。

到 的获取请求/abc需要外部重定向到,但如果 apache 检测到那是一个目录,/abc/它将自动执行该操作。/abc

一个有用的外部重定向工具是程序 wget,它可以显示服务器发送的重定向。

答案2

摘自 Jon Lin 的回答这里

URL 中的额外斜线会更改相对 URL 基数。内容中所有相对 URL 的链接现在都将使用不正确的基数。您可以使用绝对 URL(以 开头/)或在页面标题中添加基数来修复此问题:

<base href="/" />

相关内容