Мне нужна помощь с моим файлом .htaccess. Я возился с ним около недели, но не могу заставить его работать.. Я искал в Интернете решения, но ничего не подходило для моего случая.
В общем, при вводе: website.com/info.html?page=12 должно появиться: website.com/info/12
и наоборот: website.com/info/12 должен служить: website.com/info.html?page=12.
Аналогично, без части QUERY_STRING:
website.com/info.html должно показывать: website.com/info
и website.com/info должен служить: website.com/info.html.
Однако!
website.com/info/ (только если за ним ничего не следует) должно быть перенаправлено на: website.com/info.
Как я могу этого добиться? Это должно быть просто, но я пока не могу уложиться в этом.. Любые советы очень ценятся!
ОБНОВЛЯТЬ:
Спасибо за ответы и комментарии. Это, конечно, пролило некоторый свет на эту тему. Я почти на месте...
Начнем с того, что если у кого-то возникнут проблемы с пониманием регулярных выражений, эти инструменты мне очень помогли:
И аналогичный для тестирования файлов .htaccess:
https://htaccess.madewithlove.com
Некоторые уточнения:
Мне нужно общее .html скрытие для всех страниц, но только одно конкретное перенаправление с /info/ (каталога с таким именем нет) на /info.
Я прочитал параметр ?page=12 с помощью JS window.location.search, но не думаю, что это имеет значение, поскольку я могу воспроизвести ошибку на странице и без него.
Теперь мой файл .htaccess выглядит так:
RewriteEngine on
# Externally redirect: "/info.html?page=YYY" to: "/info/YYY" - WORKS
RewriteCond %{QUERY_STRING} page=(\d+) [NC]
RewriteRule ^info\.html$ /info/%1? [NC,R=302,NE,L]
# Externally redirect: "/XXX.html" to: "/XXX" - WORKS
RewriteCond %{THE_REQUEST} /(.+)\.html [NC]
RewriteRule ^ /%1 [NC,R=302,NE,L]
# Externally redirect: "/info/" to: "/info" - WORKS
RewriteRule ^info/$ /info [NC,R=302,L]
# Internally rewrite: "/info/YYY" to: "/info.html?page=YYY" - INTERNAL SERVER ERROR
RewriteRule ^info/(\d+) /info.html?page=$1 [L]
# Internally rewrite: "/XXX" to: "/XXX.html" - WORKS
RewriteCond %{REQUEST_FILENAME}.html -f [NC]
RewriteRule ^ %{REQUEST_URI}.html [NC,L]
Как и написано в комментариях, все работают кроме 4-го.
Однако, если я удалю 1-й, 4-й заработает.
Что мне не хватает??
/info.html?page=12 - Делаем шаг назад на минутку... как вы на самом деле читаете параметр URL?





Я бы начал с перенаправления всех расширений .html, чтобы они не отображались в URL.
Затем, если после него есть номер, вы можете перенаправить страницу = номер
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)\.html$ /$1 [L,R=301]
#redirect /number to ?page=number
RewriteRule ^info/([0-9]+)$ /info?page=$1 [L]
Условия первого правила предотвратят перенаправление, поскольку /info.html — это физический файл. Вам не хватает .html в строке замены во втором правиле. Но в противном случае это приведет к циклу перенаправления. А как насчет запросов на /info.html?page=12 и /info/?
Вы пишете: "website.com/info.html?page=12 должно показать: website.com/info/12...
На самом деле это не имеет особого смысла, если рассматривать переписывание URL-адресов. Конечно, вы можете перенаправить такой URL-адрес, но при этом все равно будет отображаться первый URL-адрес до того, как произойдет перенаправление. Нужно понимать, что рерайтинг работает на входящих запросах. Это никак не меняет исходящие ответы. Инструменты для этого существуют, но я сомневаюсь, что это имеет смысл в вашем случае. Вместо этого вам следует позаботиться о том, чтобы логика вашего приложения в первую очередь выдавала не этот более длинный URL-адрес, а тот, который вы действительно хотите использовать.
Перенаправление запросов с /info/ на /info, безусловно, возможно, хотя было бы тривиально просто пропустить перенаправление и напрямую доставить ожидаемый ответ. Как вам нравится. Обратите внимание, что это также может конфликтовать с другими настройками вашей настройки, о которых я ничего не знаю. Так что вам придется немного поэкспериментировать с этим.
В любом случае, это будет отправной точкой для внешнего перенаправления такого URL-адреса по запросу. И чтобы внутренне переписать входящий запрос на этот более короткий URL-адрес по желанию:
RewriteEngine on
# externally redirect https://example.com/info.html?page=12
RewriteCond %{QUERY_STRING} ^page=12$
RewriteRule ^/?info\.html$ /info/12 [R=301,L,QSD]
# externally redirect https://example.com/info.html
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^/?info\.html$ /info [R=301,L]
# optional: externally redirect https://example.com/info/
RewriteRule ^/?info/$ /info [R=301,L]
# internally rewrite requests to https://example.com/info/12
RewriteRule ^/?info/12/?$ /info.html?page=12 [L]
# internally rewrite requests to https://example.com/info
RewriteRule ^/?info/?$ /info.html [L]
Очевидно, вы можете реализовать это более общим способом:
RewriteEngine on
# externally redirect https://example.com/info.html?page=<any number>
RewriteCond %{QUERY_STRING} ^page=(\d+)$
RewriteRule ^/?info\.html$ /info/%1 [R=301,L,QSD]
# externally redirect https://example.com/info.html
RewriteCond %{QUERY_STRING} ^$
RewriteRule ^/?info\.html$ /info [R=301,L]
# optional: externally redirect https://example.com/info/
RewriteRule ^/?info/$ /info [R=301,L]
# internally rewrite requests to https://example.com/info/<any number>
RewriteRule ^/?info/(\d+)/?$ /info.html?page=$1 [L]
# internally rewrite requests to https://example.com/info
RewriteRule ^/?info/?$ /info.html [L]
Вы можете реализовать эти правила в конфигурации хоста центрального http-сервера. Это предпочтительное место для таких правил по разным причинам. Если у вас нет к нему доступа (читай: если вы используете дешевого провайдера веб-пространства), вы можете вместо этого использовать распределенный файл конфигурации (обычно называемый «.htaccess»). Для этого вам необходимо позаботиться о том, чтобы такой файл находился в папке, настроенной как DocumentRoot внутри вашего http-хоста, чтобы файл был доступен для чтения процессом http-сервера и чтобы вы включили интерпретацию таких правил в таких файлах с помощью AllowOverride директива (подробнее об этом см. в документации).
# Internally rewrite: "/info/YYY" to: "/info.html?page=YYY" - INTERNAL SERVER ERROR RewriteRule ^info/(\d+) /info.html?page=$1 [L]Я прочитал параметр
?page=12с помощью JSwindow.location.search, но не думаю, что это имеет значение
Да, это важно. Вы не можете внутренне переписать (на сервере), чтобы добавить строку запроса и ожидать, что JS на стороне клиента сможет увидеть эту строку запроса. «Внутренняя перезапись» полностью выполняется внутри сервера. JS видит только ответ, отправленный обратно с сервера, который не включает строку запроса (если только она не присутствовала в исходном запросе или вы не перенаправили на него извне).
Вместо этого вы можете внутренне переписать запрос только для /info/12 на /info.html (без строки запроса) и использовать window.location.pathname для анализа URL-пути (т. е. /info/12) для извлечения страницы из второго сегмента пути (если таковой имеется).
Что касается вашей "ошибки". Первое правило перенаправляет вновь переписанный URL-адрес во время второго прохода механизма перезаписи, что приведет к возникновению цикла перенаправления. Последнее правило также может привести к внутреннему циклу перезаписи (внутренней ошибке сервера) при определенных условиях (поскольку условие с использованием REQUEST_FILENAME не проверяет то же самое, что и REQUEST_URI). Вам также необходимо убедиться, что MultiViews отключен в этом сценарии, так как в противном случае это будет конфликтовать с вашими перезаписями.
По какой-то причине вы прибегли к использованию пустой строки запроса (в конце ?), чтобы отбросить строку запроса в первом правиле. Если вы используете Apache 2.4 (как я предполагаю), то вместо этого вам следует использовать флаг QSD (отмена строки запроса), как указано в ответе @arkascha. Хотя ваше ошибочное использование флага NC при условии проверки на -f заставляет меня усомниться в вашей версии Apache.
Я предполагаю, что вы уже ссылаетесь на канонический URL-адрес внутри своего приложения, например. /info/12 (не /info.html?page=12). И эти перенаправления предназначены только для SEO (при изменении существующей структуры URL-адресов) или для пользователей, которые могут ввести старые (неканонические) URL-адреса.
Например, попробуйте вместо этого следующее:
# Ensure that MultiViews is disabled
Options -MultiViews
RewriteEngine on
# Externally redirect: "/info.html?page=<num>" to: "/info/<num>"
RewriteCond %{QUERY_STRING} ^page=(\d+)$ [NC]
RewriteRule ^info\.html$ /info/%1 [NC,QSD,R=302,L]
# Externally redirect: "/XXX.html" to: "/XXX"
RewriteRule ^(.+)\.html$ /$1 [NC,R=302,L]
# Externally redirect: "/info/" to: "/info"
RewriteRule ^info/$ /info [NC,R=302,L]
# Internally rewrite: "/info/<num>" to: "/info.html"
RewriteRule ^info/\d+$ info.html [END]
# Internally rewrite: "/XXX" to: "/XXX.html" if it exists
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
RewriteRule (.+) $1.html [END]
Я использовал END (требуется Apache 2.4) в последних двух правилах, чтобы предотвратить второй цикл механизма перезаписи, который в противном случае привел бы к циклу перенаправления.
Также обратите внимание на добавление привязки конца строки ($) к исходному регулярному выражению ^info/(\d+), в противном случае вы разрешаете URL-адреса формы /info/12<anything>.
Я удалил префикс косой черты в строках замены двух перезаписей, поскольку мы переписываем путь к файлу, а не путь к URL-адресу. Переписывая URL-путь (префикс косой черты), вы (без необходимости) заставляете механизм перезаписи пересопоставлять URL-адрес с файловой системой.
Вы должны быть осторожны при проверке THE_REQUEST, поскольку сюда также входит строка запроса (если таковая имеется), которую вам следует избегать при проверке .html.
И, как уже упоминалось, вам нужно будет использовать window.location.pathname в JS на стороне клиента вместо этого для анализа номера страницы (если есть) из запрошенного URL-адреса.
Обратите внимание, что это можно дополнительно оптимизировать/упростить, если мы узнаем больше о вашей системе/структуре URL-адресов. Например, вы имеете дело только с URL-адресами в корне документа, как в вашем примере, или вы также ожидаете /foo/bar/baz? Содержат ли ваши URL-адреса точки? (В противном случае это привело бы к разделению расширений файлов на ваших статических ресурсах.)
«Я возился с этим около недели» — Итак, что ты пробовал? И что происходит? Есть ли у вас какие-либо другие директивы в вашем
.htaccessфайле? И я предполагаю, что/infoне сопоставляется с физическим каталогом? (Может быть, есть что-то более фундаментальное, что мешает этому работать, или просто небольшая поправка к существующим правилам.) Это только дляinfoили вам нужно что-то более общее?