web-dev-qa-db-ja.com

.htaccessmod_rewriteリダイレクトが多すぎます

明確にするために、これは this one のような重複した質問ではありません。質問のコアが異なるためです。私がやろうとしているのは、言語コード(通常はenまたはcz)を使用してサイトにアクセスしようとするユーザーを、言語変数が設定されたindex.phpにリダイレクトすることです。サイト自体は英語とチェコ語の設定のみを認識でき、他のすべては訪問者のIPジオロケーションに基づいてリダイレクトされます(外部のオンラインJSON APIを使用)。しかし、問題は、ブラウザがリダイレクトを繰り返し続け、リダイレクトが多すぎるというエラーを返すことです。どうしましたか?エラーを探しようとしましたが、何も表示されませんでした。

これは完全な.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バリアントにリダイレクトする必要があります。オンラインで検索しましたが、複雑すぎるようです:(

オンラインで展開する準備ができる前に、Windowsマシン上のWAMPサーバーでサイトをテストしています。

2
Polda18

リダイレクトループをトリガーするリクエストしているURLを実際に述べていませんか?

ただし、投稿したディレクティブから、/blog<anything>または/ftp<anything>の形式のリクエストはリダイレクトループを引き起こすように思われます。

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

Apache mod_rewriteは、RewriteRulesubstitutionのプロトコル相対URLをサポートしていません-それらは単にルート相対(つまり、ドキュメントルートに相対的な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]

リダイレクトをすぐにトリガーし、さらに書き換えられるリスクを冒さないようにするため、Llast)フラグも含めました。これは、実際には内部書き換え(index.phpに書き換える)の前に行う必要があります。

誤った301(permanent)リダイレクトがブラウザによってキャッシュされるため、ブラウザのキャッシュをクリアしたことを確認する必要があります。このため、302(一時)リダイレクトを使用するとテストが簡単になる場合があります。

blogおよびftpルールは、alternationを使用して、単一のディレクティブで処理できます。例えば:

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

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

RewriteRulepatternにキャプチャグループ(つまり、括弧で囲まれたサブパターン)がないため、$1後方参照は常に空になります。これは次のように書き直す必要があります。

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

繰り返しになりますが、それ以上の書き換えを防ぐために、Lフラグを含めました。これは、URLパスの末尾にスラッシュサフィックスがあることを想定していることに注意してください。したがって、/blog/en/(スラッシュサフィックス付き)の形式のURLのみが正常に書き換えられます(ただし、これは無関係かもしれません)。

したがって、要約すると、これは次のように書き直す必要があります。

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バリアントにリダイレクトする必要があります。

追加のリダイレクトでこれを行うことができますbefore上記のディレクティブ。例えば:

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

クエリ文字列をQUERY_STRINGサーバー変数と照合するには、RewriteCondディレクティブを使用する必要があります(これは、RewriteRuleディレクティブでは実行できません)。 REDIRECT_STATUS環境変数に対する前述のチェックは、URLを/index.php?lang=xyzに書き換える後のディレクティブによって、最初のリクエストのみを処理し、書き換えられたリクエストを処理しないことを確認することです。 REDIRECT_STATUS env varは最初のリクエストでは空ですが、最初に成功した後(200 OK-HTTPステータスのように)「200」に設定されます書き換え

これは、index.phpまたは空のURLパス(例:/?lang=xyz)のいずれかに一致します。 %1は最後に一致したCondPatternへの後方参照です(RewriteRulepatternへの後方参照である$Nとは対照的です) 。リダイレクトされたURLからクエリ文字列を削除するには、RewriteRulesubstitutionの末尾にある?が必要です(または、QSDを使用できます) Apache 2.4以降のフラグ)。

繰り返しになりますが、ブラウザによってキャッシュされない302(一時的な)リダイレクトを使用して最初にテストするのが最善です。

(コメントから:)正しく機能するのは、/ftp/リダイレクトだけです。 /blog/リダイレクトは空白のページに変更されていないURLのままです

同じ名前の物理ディレクトリがファイルシステムにないことを確認する必要があります。 /blog。また、このサブディレクトリには、これを上書きする可能性のある追加の.htaccessファイルがありません。また、同じベース名blogを共有するfileがないことを確認してください。例えば。 blog.htmlまたはblog.phpなど。ある場合は、MultiViews(mod_negotiationの一部)が有効になっていないことを確認する必要があります。すなわち。 Options -Indexes -MultiViews。 MultiViewsが有効になっている場合、Apacheはmod_rewriteがURLを書き換える前に、(たとえば)/blog.phpの内部サブリクエストを作成します。

概要

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]
3
MrWhite