Назад | Перейти на главную страницу

Как 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 (выразительный путь) и отображается страница, которая хранится внутри 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-адресу.

Я хочу сохранить относительную загрузку источников, так что если мне когда-нибудь придется переместить всю файловую систему в другой поддомен или около того, я могу просто скопировать все это. Без этого ограничения я мог бы просто сделать все нагрузки абсолютными.

Скопировано из ответа Джона Линя Вот

Дополнительная косая черта в URL изменяет относительную базу URL. Все ваши ссылки, которые являются относительными URL-адресами в вашем контенте, теперь будут использовать неправильную базу. Вы можете исправить это, используя абсолютный URL-адрес (начинается с /) или добавьте базу в шапку страницы:

<base href="/" />

Как вы выяснили, вы должны сохранить 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, она может отображать перенаправления, которые отправляет сервер.