Как 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-маршрутизация.
Давайте начнем с случая, который работает:
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
(выразительный путь) и отображается страница, которая хранится внутри example.com/httpdocs/main.html
(безобразный путь). Пользователь никогда не видит внутренний путь; 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
нужен внешний редирект на /abc/
, но apache сделает это автоматически, если обнаружит, что /abc
это каталог.
Полезным инструментом для внешних перенаправлений является программа wget, которая может отображать перенаправления, которые отправляет сервер.
Скопировано из ответа Джона Линя здесь
Дополнительная косая черта в URL изменяет относительную базу URL. Все ваши ссылки, которые являются относительными URL-адресами в вашем контенте, теперь будут использовать неправильную базу. Вы можете исправить это, используя абсолютный URL-адрес (начинается с
/
) или добавьте базу в шапку страницы:
<base href="/" />