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

.htaccess mod_rewrite слишком много перенаправлений

Чтобы прояснить ситуацию, это НЕ повторяющийся вопрос, например вот этот поскольку суть вопроса в другом. Я пытаюсь перенаправить пользователей, которые пытаются получить доступ к сайту, используя языковой код (обычно en или cz) к index.php с установленной языковой переменной. Сам сайт может распознавать только настройки английского и чешского языков, все остальные перенаправляются на основе геолокации IP посетителя (с использованием внешнего онлайн-API JSON). Но проблема в том, что этот браузер продолжает перенаправлять и выдает ошибку о том, что произошло слишком много перенаправлений. В чем дело? Пытался найти ошибку, но ничего не обнаружил.

Это завершено .htaccess файл:

Options -Indexes

RewriteEngine on
RewriteRule ^[a-z]{2,3}/$ /index.php?lang=$1
RewriteRule ^blog/?(.*)$ //blog.czghost.czlh/$1 [R=301]
RewriteRule ^ftp/?(.*)$ //ftp.czghost.czlh/$1 [R=301]

Также, если пользователь пишет в index.php?lang=$1, Мне нужно вместо этого перенаправить его на хороший вариант URL. Я искал в Интернете, но мне это кажется слишком сложным :(

Я тестирую сайты на своем сервере WAMP на своем компьютере с Windows, прежде чем он будет готов к развертыванию в Интернете.

Вы фактически не указали запрашиваемые URL-адреса, которые запускают цикл перенаправления?

Однако из опубликованных вами директив может показаться, что любой запрос формы /blog<anything> или /ftp<anything> приведет к возникновению цикла перенаправления.

RewriteRule ^blog/?(.*)$ //blog.czghost.czlh/$1 [R=301]
RewriteRule ^ftp/?(.*)$ //ftp.czghost.czlh/$1 [R=301]

Apache mod_rewrite не поддерживает URL-адреса, относящиеся к протоколу, в RewriteRule замена - они просто рассматриваются как относительные к корню (т. е. путь URL относительно корня документа). Вы, вероятно, видите результат этого цикла перенаправления в адресной строке своего браузера? Это будет примерно так:

  • Первоначальный запрос: http://example.com/blog/xyz
  • Перенаправляет на http://example.com//blog.czghost.czlh/xyz
  • Перенаправляет на http://example.com//blog.czghost.czlh/.czghost.czlh/xyz
  • Перенаправляет на http://example.com//blog.czghost.czlh/.czghost.czlh/.czghost.czlh/xyz
  • и т.п.

Вам нужно включить протокол. Например:

RewriteRule ^blog/?(.*)$ https://blog.czghost.czlh/$1 [R=301,L]

Я также включил L (last), поскольку вы хотите, чтобы перенаправление запускалось немедленно, не подвергайтесь риску дальнейшей перезаписи. Это действительно должно произойти до внутренней перезаписи (которая переписывает на index.php).

Вам нужно будет убедиться, что вы очистили кеш браузера, так как ошибочный 301 (постоянный) перенаправление будет кешировано браузером. По этой причине может быть проще протестировать с 302 (временными) перенаправлениями.

Ваш blog и ftp правила могут обрабатываться одной директивой, используя чередование. Например:

RewriteRule ^(blog|ftp)/?(.*)$ https://$1.czghost.czlh/$2 [R=301,L]

RewriteRule ^[a-z]{2,3}/$ /index.php?lang=$1

У вас нет группы захвата (т. Е. Заключенного в скобки подшаблона) в RewriteRule шаблон, так что $1 обратная ссылка всегда будет пустой. Это следует переписать как:

RewriteRule ^([a-z]{2,3})/$ /index.php?lang=$1 [L]

Опять же, я включил L флаг, чтобы предотвратить дальнейшую перезапись. Обратите внимание, что ожидается, что в конце пути URL будет суффикс косой черты. Итак, только URL-адреса формы /blog/en/ (с суффиксом косой черты) будет успешно переписан (хотя, возможно, это не связано).

Итак, вкратце, это следует переписать примерно так:

RewriteRule ^(blog|ftp)/?(.*)$ https://$1.czghost.czlh/$2 [R=301,L]
RewriteRule ^([a-z]{2,3})/$ /index.php?lang=$1 [L]

Также, если пользователь пишет в index.php?lang=$1, Мне нужно вместо этого перенаправить его на хороший вариант URL.

Сделать это можно с помощью дополнительного редиректа перед вышеуказанные директивы. Например:

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^lang=([a-z]{2,3})$
RewriteRule ^(index\.php)?$ /%1/? [R=301,L]

Вам нужно использовать RewriteCond директива для проверки строки запроса на соответствие QUERY_STRING серверная переменная (этого нельзя сделать в RewriteRule директива). Предыдущая проверка по REDIRECT_STATUS переменная среды, чтобы убедиться, что мы обрабатываем только начальные запросы, а не перезаписываем запросы более поздней директивой, которая перезаписывает URL-адрес на /index.php?lang=xyz. В REDIRECT_STATUS env var пуст при первоначальном запросе, но получает значение "200" (как в 200 OK - статус HTTP) после первого успешного переписать.

Это будет соответствовать либо index.phpили пустой путь URL (например, /?lang=xyz). %1 это обратная ссылка на последнее совпадение CondPattern (в отличие от $N это обратная ссылка на RewriteRule шаблон). В ? в конце RewriteRule замена необходимо, чтобы удалить строку запроса из перенаправленного URL-адреса (в качестве альтернативы вы можете использовать QSD флаг на Apache 2.4+).

Опять же, лучше всего сначала протестировать с 302 (временным) перенаправлением, которое не будет кэшироваться браузером.

(Из комментариев :) Единственное, что работает правильно, это /ftp/ перенаправить. /blog/ перенаправление остается с неизменным URL-адресом на пустой странице

Вы должны убедиться, что в файловой системе нет физического каталога с тем же именем, т.е. /blog. И что в этом подкаталоге нет дополнительных .htaccess файл, который может переопределить это. Также убедитесь, что нет файл с таким же базовым именем blog. например. blog.html или blog.php и т.д. Если есть, то вам нужно убедиться, что MultiViews (часть mod_negotiation) не включен. т.е. Options -Indexes -MultiViews. Если MultiViews включен, Apache выполнит внутренний подзапрос для /blog.php (например) до того, как mod_rewrite сможет перезаписать URL.

Резюме

Options -Indexes -MultiViews

RewriteEngine on

# Redirect direct requests for "index.php?lang=xyz" to "/xyz/"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^lang=([a-z]{2,3})$
RewriteRule ^(index\.php)?$ /%1/? [R=301,L]

# Redirect "blog" or "ftp/<anything>" to subdomain
RewriteRule ^(blog|ftp)/?(.*)$ https://$1.czghost.czlh/$2 [R=301,L]

# Internally rewrite "/xyz/" to "/index.php?lang=xyz"
RewriteRule ^([a-z]{2,3})/$ /index.php?lang=$1 [L]