我在服务器上有一个丑陋的文件系统路径: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="/" />