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

mod_rewrite: перезаписать существующий файл в slug, slug в существующий файл

Моя ситуация такова: у меня есть статические файлы в папке public/ на моем локальном сервере. Любой входящий запрос должен быть перенаправлен в эту папку, но если к файлу в этой папке осуществляется прямой доступ, он должен быть либо 404, либо перенаправлен на «slug». Пример:

Request: /my-file
Should rewrite to: /public/my-file.html
URL should be: http://localhost/my-file

Request: /public/my-file.html
Should rewrite to: /public/my-file.html
URL should be: http://localhost/my-file

У меня есть следующие правила и условия в моем .htaccess:

RewriteCond %{DOCUMENT_ROOT}/public/%{REQUEST_URI}.html -f
RewriteRule ^.*$ /public/$0.html [L,C]
RewriteCond %{REQUEST_URI} ^/public
RewriteRule ^public/(.+).html$ /$1 [R=301,L]

Сверху донизу:

  1. Является /public/{request}.html файл?
  2. Перепишите, если (1) верно: /public/{request}.html, и цепочку к (3), чтобы предотвратить цикл перенаправления
  3. Исходный запрос начинается с /public?
  4. Перепишите, если (3) истинно, и исходный запрос соответствует public/{request}.html: /{request}. Также сделайте 301 заголовок, который сообщает моему браузеру и поисковым роботам, что страница переместилась навсегда. Запрос снова пройдет по всем правилам

Итак, если мы выполним эти два запроса:

1. Request: /my-file
  1. /public/my-file.html оценивается как истина; файл существует в моей папке.
  2. Переписывает на: /public/my-file.html, цепочка до 3
  3. Исходный запрос не соответствует.
  4. Пропущено

Все идет нормально; отображается нужный файл с нужным мне URL. Запрос номер 2, который представляет собой запрос фактического файла в том виде, в каком он существует в файловой структуре:

2. Request: /public/my-file.html
  1. public/public/my-file.html.html принимает значение false, файл не существует в моей папке.
  2. Пропущено
  3. Исходный запрос совпадает: он начинается с /public
  4. Переписать public/my-file.html к /my-file, и идти сверху.

Теперь, после (4) во 2-м примере, я бы сказал, что запрос соответствует 1-му примеру, что означает, что я получаю страницу, которую ищу, с правильным URL-адресом (из-за 301). Но это не работает: URL-адрес не меняется, я получаю страницу, которую ищу, но не URL-адрес (который должен быть /my-file).

У кого-нибудь есть указатели? Я думаю, что почти готов, но что-то не так с цепочкой или перенаправлением. Спасибо!

редактировать

Перепробовав всевозможные вещи, я наконец решил, что то, что я хочу, вероятно, невозможно. Я хочу перенаправить существующий файл (public/my-file.html) в несуществующий файл (my-file) визуально, но внутри я хочу, чтобы он запрашивал существующий путь к файлу. Это неизбежно приведет к циклу перенаправления, потому что mod_rewrite просто так не работает:

User typed: website.com/my-file
Rewrites to file path: .../wwwroot/public/my-file.html
Internal redirect
Rewriterule found: /public/my-file.html should redirect to my-file
See above.

Я не встречал подобной ситуации здесь, на ServerFault или StackOverflow - обычно переписывание идет на общий .php файл, а не существующий .html файл.

Я отметил ответ Криста ван Бесиена как правильный, поскольку он указал мне правильное направление для понимания всего этого.

Редактировать 2

В следующем вопросе проблема была решена с помощью %{THE_REQUEST}: Посмотреть здесь

Вы можете просто проверить наличие реальных файлов / папок и пропустить ...

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

Вы можете иметь несколько Cond перед правилом.

То, что это не работает должным образом, связано с порядком выполнения RewriteConds и RewriteRules. RewriteRules оцениваются перед RewriteConds, которые им предшествуют. Итак, закажите ваш запрос на /public/my-file.htmlобрабатывается так: (Я сохраню вашу нумерацию)

  • Сначала URL проверяется на соответствие тестовому шаблону 2. И это соответствует..* в конце концов соответствует чему угодно ..
  • Затем оценивается RewriteCond 1. Поскольку это не удается, замена в 2 не выполняется.
  • URI сравнивается с тестовым шаблоном 4. Этот тестовый шаблон не соответствует, поскольку ваш URI начинается с /. Правило не работает, поэтому RewriteCond на 3 никогда не оценивается.

RewriteConds (а у вас может быть несколько) принадлежат RewriteRule, которое следует за ними, и оцениваются только в том случае, если сначала совпадает шаблон в RewriteCond. Я знаю, это немного нелогично.

О синтаксисе читайте здесь: Перенаправление, изменение URL-адресов или перенаправление HTTP на HTTPS в Apache - все, что вы когда-либо хотели знать о правилах Mod_Rewrite, но боялись спросить

Как решить вашу проблему?

Может что-то вроде:

RewriteRule  ^/public/(.*)$     /$1 [R=301,L]
RewriteRule  ^(-*)$             /public/$1

И последний совет: включите журнал перезаписи. Выучите связку ...