リダイレクト
リダイレクトについて
リダイレクトはページを転送したり、URLを書き換えたりすることができ、古いWebサイトから新しいWebサイトへの移転をはじめ、端末ごとの振り分けやURLの正規化など様々な用途で使えます。
このページでは主にリダイレクトの例を紹介します。
RewriteとRedirectの違い
RewriteはURLの書き換えが発生せず(URLそのまま)、RedirectはURLが書き換えられるため転送したようにページ遷移します。
URLの書き換えが発生しないというのは、あたかもそのURLが本来のURLのように振る舞うという意味で、リライト先が画像の場合はそのまま画像が表示されます。
書き方はほぼ同じで、末尾のフラグ(オプションのようなもの)の指定の違いのみです。
Rewrite例:URL書き換えなし
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^test[/]?$ /tmp/test.jpg [L] </IfModule>
Redirect例:アクセスするとリダイレクト先に転送される(URL書き換えあり)
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^test[/]?$ /tmp/test.jpg [L,R=302] </IfModule>
「L」はそれ以降のルールは無視するという意味で、「R=302」は一時的なリダイレクトの意味です。
RewriteRuleで「R=」を付けない場合はRewrite(URL書き換え無し)になるということですね。
基本的な記述方法とフラグ
RewriteRule
RewriteRuleは条件と転送先を1行で書きます。
簡単な転送の場合はこれで行います。
RewriteRule 旧ページ 新ページ [フラグ]
例えば old.html から new.html へ、301で転送する場合は以下のような感じです。
RewriteRule old.html$ new.html [R=301,L]
RewriteCond
RewriteCondは条件だけを記述し、その次に来るRewriteRuleで転送を行います。
RewriteCondは連続して複数記述することができ、末尾に [OR] フラグがあると、その次の条件とはORで判定されます。
例えば以下の XXX と YYY は「XXX OR YYY」という感じで評価されます。
RewriteCond XXX [OR] RewriteCond YYY RewriteRule ***
大文字小文字を区別しない [NC] フラグなどと併用する場合はカンマで区切って記述します。
RewriteCond XXX [OR,NC] RewriteCond YYY [NC] RewriteRule ***
[OR] が指定されていない場合はANDとして評価されます。
RewriteCond XXX RewriteCond YYY RewriteRule ***
RewriteCond XXX [NC] RewriteCond YYY [NC] RewriteRule ***
OR と AND が混ざってくると結構ややこしいので、場合によっては別の条件として分けて記述した方が後で分かりやすい場合もあります。
リダイレクトの実例
ページ単位のリダイレクト
old.html にアクセスされると、https://sakue.com/new.html へ転送します。
一時的なリダイレクトの場合は「R=301」を「R=307」もしくは「R=302」にします。
<IfModule mod_rewrite.c> RewriteEngine on RewriteBase / RewriteRule old.html$ https://sakue.com/new.html [R=301,L] </IfModule>
同じサイト&ディレクトリ内の場合
<IfModule mod_rewrite.c> RewriteEngine on RewriteBase / RewriteRule old.html$ new.html [R=301,L] </IfModule>
WordPressのパーマリンク変更例
<IfModule mod_rewrite.c> RewriteEngine on RewriteBase / RewriteRule ^wordpress/2020/08/26/さくらインターネットのwordpress/$ "https://sakue.com/archives/136" [R=301,L] RewriteRule ^wordpress/2020/08/27/windows10の各種ファイルの保存先/$ "https://sakue.com/archives/155" [R=301,L] RewriteRule ^wordpress/2020/08/27/wordpressのメールとさくら/$ "https://sakue.com/archives/176" [R=301,L] RewriteRule ^wordpress/2020/08/27/hdmiキャプチャデバイス対決/$ "https://sakue.com/archives/182" [R=301,L] RewriteRule ^wordpress/2020/08/27/さくらインターネットと常時ssl/$ "https://sakue.com/archives/187" [R=301,L] </IfModule>
日本語の場合はそのまま日本語で記述しますが、.htaccessの文字コードは「UTF-8」で保存してください。
ディレクトリ単位のリダイレクト
例えば https://sakue.com/old/test.html へアクセスされると、 https://sakue.com/new/test.html などへリダイレクトされます。
<IfModule mod_rewrite.c> RewriteEngine on RewriteBase / RewriteRule ^old(.*)$ /new$1 [R=301,L] </IfModule>
一部で正規表現での記述がありますが、
「^」は~で始まる
「(.*)」は任意の文字列
「$1」は1番めの括弧の文字列を利用するという意味です(後方参照)
WordPressでディレクトリを変更した場合の例です。
<IfModule mod_rewrite.c> RewriteEngine on RewriteBase / RewriteRule ^wordpress/archives/(.*)$ /archives/\ [R=301,L] </IfModule>
https://sakue.com/wordpress/archives/~ を https://sakue.com/archives/~ へ転送します。
ドメイン単位のリダイレクト
ドメインを変更したけど、ディレクトリやファイルの構成は全く同じで、ドメインだけ引っ越したような場合の例です。
<IfModule mod_rewrite.c> RewriteEngine on RewriteBase / RewriteCond %{HTTP_HOST} ^(old.com) [NC] RewriteRule ^(.*) https://new.jp/\ [R=301,L] </IfModule>
パラメータ付きURLの簡略化
https://sakue.com/cam1 へアクセスすると、https://sakue.com/cgi-bin/zm/nph-zms?mode=single&monitor=1&scale=100 の情報を表示します(URLはそのまま)
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^cam1/$ /cgi-bin/zm/nph-zms?mode=single&monitor=1&scale=100 [L] RewriteRule ^cam2/$ /cgi-bin/zm/nph-zms?mode=single&monitor=2&scale=100 [L] RewriteRule ^cam3/$ /cgi-bin/zm/nph-zms?mode=single&monitor=3&scale=100 [L] </IfModule>
ファイル/ディレクトリが存在しない場合にindex.phpに飛ばす
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] </IfModule>
特定ディレクトリの除外
まとめて転送するけど、特定のディレクトリやファイルは除外したい場合の指定方法です。
<IfModule mod_rewrite.c> RewriteEngine on RewriteBase / RewriteCond %{REQUEST_URI} !(^/除外ディレクトリ名/) RewriteRule ^$ https://sakue.com/ [R=301,L] </IfModule>
複数ある場合は続けて記述します。
<IfModule mod_rewrite.c> RewriteEngine on RewriteBase / RewriteCond %{HTTP_HOST} ^(sakue.com) [NC] RewriteCond %{REQUEST_URI} !(^/SnapShot/) RewriteCond %{REQUEST_URI} !(^/tmp/) RewriteRule ^(.*) https://new.jp/\ [R=301,L] </IfModule>
上記の除外例では条件は全て「AND」として扱われるため、以下のような意味になります。
- ホスト名がsakue.comで始まっている
- かつ、URIが /SnapShot/ から開始ではない
- かつ、URIが /tmp/ から開始でもない
上記の条件を満たす場合に転送する。という意味です。
「OR」の場合は [OR] や、フラグと併用する場合は [OR,NC] などと記述しますが、ANDと違って少しややこしいので注意しましょう。
wwwなしのURLに統一
例えば https://www.sakue.com を https://sakue.com にします。
サブディレクトリなども全てwww無しになります。
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{HTTP_HOST} ^www\.sakue\.com RewriteRule ^(.*) https://sakue.com/\ [R=301,L] </IfModule>
www有りのURLに統一
例えば https://sakue.com を https://www.sakue.com にします。
サブディレクトリなども全てwww有りになります。
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{HTTP_HOST} ^sakue\.com RewriteRule ^(.*) https://www.sakue.com/\ [R=301,L] </IfModule>
index.html無しのURLに統一
一般的なWebサーバはファイル名まで指定せず、ディレクトリで終わっている場合は「index.html」などを返しますが、URLから「index.html」を除去してスッキリさせます。
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{THE_REQUEST} ^.*/index.html RewriteRule ^(.*)index.html$ https://sakue.com/\ [R=301,L] </IfModule>
index.phpの場合も同様です
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{THE_REQUEST} ^.*/index.php RewriteRule ^(.*)index.html$ https://sakue.com/\ [R=301,L] </IfModule>
index.html、index.phpの両方に対応し、転送先のホスト名も環境変数から取る場合の例です。
<IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{THE_REQUEST} ^.*/index.(html|php) RewriteRule ^(.*)index.(html|php)$ https://%{HTTP_HOST}/\ [R=301,L] </IfModule>
httpからhttpsへリダイレクト(常時SSL)
<IfModule mod_rewrite.c> RewriteEngine on RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] </IfModule>
httpからhttpsへリダイレクト(一部除外)
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / # HTTPでアクセスされた場合、 RewriteCond %{HTTPS} off # 以下のURLは常に https にリダイレクトする RewriteCond %{HTTP_HOST} sakue.com RewriteCond %{REQUEST_URI} ^/admin/.*$ [OR] RewriteCond %{REQUEST_URI} ^/inquiry/.*$ # ただし以下は除く RewriteCond %{REQUEST_URI} !^/assets/.*$ RewriteCond %{REQUEST_URI} !^.*\.(js|css|gif|jpg|png|ico)$ # https にリダイレクト RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L] </IfModule>
httpsからhttpへリダイレクト(一部除外)
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / # HTTPSでアクセスされた場合、 RewriteCond %{HTTPS} on # 以下のURL以外は常に http にリダイレクトする RewriteCond %{HTTP_HOST} sakue.com RewriteCond %{REQUEST_URI} !^/admin/.*$ RewriteCond %{REQUEST_URI} !^/inquiry/.*$ # ただし以下は除く RewriteCond %{REQUEST_URI} !^/assets/.*$ RewriteCond %{REQUEST_URI} !^.*\.(js|css|gif|jpg|png|ico)$ # http にリダイレクト RewriteRule ^.*$ http://%{HTTP_HOST}%{REQUEST_URI} [R,L] </IfModule>
httpとhttpsの転送(混合)
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / # (1) HTTPでアクセスされた場合、 RewriteCond %{HTTPS} off # 以下のURLは常に https にリダイレクトする RewriteCond %{HTTP_HOST} sakue.com RewriteCond %{REQUEST_URI} ^/admin/.*$ [OR] RewriteCond %{REQUEST_URI} ^/inquiry/.*$ # ただし以下は除く RewriteCond %{REQUEST_URI} !^/assets/.*$ RewriteCond %{REQUEST_URI} !^.*\.(js|css|gif|jpg|png|ico)$ # https にリダイレクト RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L] # (2) HTTPSでアクセスされた場合、 RewriteCond %{HTTPS} on # 以下のURL以外は常に http にリダイレクトする RewriteCond %{HTTP_HOST} sakue.com RewriteCond %{REQUEST_URI} !^/admin/.*$ RewriteCond %{REQUEST_URI} !^/inquiry/.*$ # ただし以下は除く RewriteCond %{REQUEST_URI} !^/assets/.*$ RewriteCond %{REQUEST_URI} !^.*\.(js|css|gif|jpg|png|ico)$ # http にリダイレクト RewriteRule ^.*$ http://%{HTTP_HOST}%{REQUEST_URI} [R,L] </IfModule>
404のエラーを返す
リモートホストを返す環境変数の %{REMOTE_HOST} を使う場合は、httpd.confで以下を有効にする必要があります。
エラーは出ませんが、ホスト名が取れないので一致しません。
HostnameLookups On
特定のIPやホストからのアクセスは404を返す
「~または~」というORの条件の場合は末尾に [OR] を付けます。
以下の例ではIPアドレスが「192.168.2.2」または「192.168.2.3」の場合に404を返します。
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REMOTE_ADDR} ^192\.168\.2\.2$ [OR] RewriteCond %{REMOTE_ADDR} ^192\.168\.2\.3$ RewriteRule ^.*$ - [R=404,L] </IfModule>
改行をなくすと「XXX OR YYY」のようになるので、最後の要素には付けないという感じです。
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REMOTE_ADDR} ^192\.168\.2\..*$ [OR] RewriteCond %{REMOTE_ADDR} ^192\.168\.3\..*$ [OR] RewriteCond %{REMOTE_ADDR} ^192\.168\.4\..*$ RewriteRule ^.*$ - [R=404,L] </IfModule>
フラグと併用する場合は[]内にカンマ区切りで記述します。
例えば大文字・小文字を区別しない [NC] と併用する場合は [OR,NC] のように書きます。
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REMOTE_HOST} ^.*\.aaa\.jp$ [OR,NC] RewriteCond %{REMOTE_HOST} ^.*\.bbb\.jp$ [OR,NC] RewriteCond %{REMOTE_HOST} ^.*\.ccc\.jp$ [OR,NC] RewriteCond %{REMOTE_HOST} ^.*\.ddd\.jp$ RewriteRule ^.*$ - [R=404,L] </IfModule>
特定のIPやホスト「以外」は404を返す
404のエラーを返す場合はフラグで「R=404」を指定します。
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REMOTE_ADDR} !^192\.168\.2\.*$ RewriteCond %{REMOTE_HOST} !^.*.ppp\.infoweb\.ne\.jp$ RewriteRule ^.*$ - [R=404,L] </IfModule>
[OR] が記述されていない場合はANDの条件になりますので、上記の例はIPアドレスが「192.168.2.」でなく、かつホスト名が「.ppp.infoweb.ne.jp」でもない場合に404のエラーを返します。
環境変数による振り分け
ちょっと長くなってしまったので条件の例だけ記載します。
例の末尾のほとんどに [NC] というフラグがついていますが、大文字・小文字を区別しないというフラグなので、区別する場合は外してください。
列挙していく場合、末尾に [OR] が無い場合は「AND」になる点に注意してください。
[NC] フラグと併用する場合は [OR,NC] のようにカンマ区切りで記述します。
ユーザーエージェントで振り分け
RewriteCond %{HTTP_USER_AGENT} ".*Android.*" [NC]
サーバーのホスト名で振り分け
RewriteCond %{HTTP_HOST} "^.*\.sakue\.com" [NC]
リファラで振り分け(直前のURL)
RewriteCond %{HTTP_REFERER} "^.*\.sakue\.com" [NC]
IPアドレスで振り分け
RewriteCond %{REMOTE_ADDR} "^192\.168\..*" [NC]
リモートホスト名で振り分け
RewriteCond %{REMOTE_HOST} "^.*\.sakue\.com" [NC]
リモートホストで振り分けする場合は httpd.conf で以下を有効にする必要があります。
エラーは出ないもののホスト名が取得できないので一致してくれません。
HostnameLookups On
ユーザー名で振り分け
RewriteCond %{REMOTE_USER} "^admin$" [NC]
リクエストメソッド(GET/POST)で振り分け
RewriteCond %{REQUEST_METHOD} "^(GET|POST)$" [NC]
日付で振り分け
環境変数の%{TIME_YEAR}に4桁の年が、%{TIME_MON}に2桁の月が、%{TIME_DAY}に2桁の日が格納されています。
2020/10/21以降
RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY} ">20201021"
2020/10/21以前
RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY} "<20201021"
2020/10/21と等しい
RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY} "=20201021"
時刻で振り分け
環境変数の%{TIME_HOUR}と%{TIME_MIN}に、それぞれ2桁の「時」と「分」が格納されていますので、それで判断します。
08時以前
RewriteCond %{TIME_HOUR}%{TIME_MIN} "<0800"
18時以降
RewriteCond %{TIME_HOUR}%{TIME_MIN} ">1800"
曜日で振り分け
曜日は「日曜日を0」とした数字が格納されていますので、それで判断します。
日曜
RewriteCond %{TIME_WDAY} "0"
月曜
RewriteCond %{TIME_WDAY} "1"
火曜
RewriteCond %{TIME_WDAY} "2"
水曜
RewriteCond %{TIME_WDAY} "3"
木曜
RewriteCond %{TIME_WDAY} "4"
金曜
RewriteCond %{TIME_WDAY} "5"
土曜
RewriteCond %{TIME_WDAY} "6"
平日
RewriteCond %{TIME_WDAY} ">0" RewriteCond %{TIME_WDAY} "<6"
動作確認
Chromeのデベロッパーツール
「…」から、その他のツール > 「デベロッパーツール」に進みます。
「Network」タブを開きます。
「Preserve log」にチェックを入れます。
このチェックをONにすると、ページが移動(今回のリダイレクト)してもログがクリアされません。
逆にOFFの状態だとリダイレクトや更新ボタンなどの際に毎回ログがクリアされます。
テスト中にキャッシュを使わないように「Disable cache」にもチェックを入れておきます。
この状態でリダイレクト設定があるページを開いて確認します。
「Status」の列に注目してみると、302(一時的な移動)でリダイレクトされているのが確認できます。
Firefoxの開発者ツール
Firefoxの開発者ツールでリダイレクトを追うこともできます。
ツール > ウェブ開発 > 開発者ツールを表示
「ネットワーク」タブを開きます。
テスト中にキャッシュが使われないよう「キャッシュを無効化」にもチェックを入れてください。
そのままだとページが遷移するとログもクリアされてしまい、リダイレクトが追えないため、「永続ログ」にチェックを入れます。
ログがゴチャゴチャして邪魔な場合は左にある「ゴミ箱」アイコンをクリックするとログがクリアされます。
開発者ツールのネットワークタブを開いたまま、リダイレクトがあるページを開いてみます。
左端に「ステータス」という項目がありますが、3から始まるステータスコード(301や302など)が転送を意味するものです。
以下の例では302(一時的な移動)が返ってきているのが分かります。
番外:リバースプロキシ
ここで説明するリダイレクトとは関係ありませんが、似た動きをするリバースプロキシも簡単に説明しておきます。
リバースプロキシはWebサーバの前段に置いて、代理でコンテンツを取得してきて表示するような機能です。
apacheの例だと、以下のように設定した場合、「/cam1」へアクセスされた場合は「http://localhost:8081」の内容を表示します。
URLの書き換えが発生せず、あたかもそこにあるように振る舞うため、本来のサーバの隠蔽や負荷分散などにも使われます。
ProxyPass /cam1 http://localhost:8081 ProxyPassReverse /cam1 http://localhost:8081
設定自体は非常に簡単なので以下にメモしておきます。
プロキシモジュールを有効にする
最近のApacheでは /etc/httpd/conf.modules.d/ へ「LoadModule」行が分離されており、httpd.confで「Include conf.modules.d/*.conf」の行があれば全て読み込まれているので特に設定する必要はありません。
少し前のApacheでは以下の行を有効にします。
Linux版の場合
LoadModule proxy_module libexec/mod_proxy.so LoadModule proxy_http_module libexec/mod_proxy_http.so
Windows版の場合
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so
httpd.confへ追加
以下のような感じで記述します。
複数ある場合はProxyPass行をまとめて書き、その後にProxyPassReverse行をまとめて書きます。
ProxyPass /cam1 http://localhost:8081 ProxyPass /cam2 http://localhost:8082 ProxyPassReverse /cam1 http://localhost:8081 ProxyPassReverse /cam2 http://localhost:8082
以下のような順序で書くと、2番目に記述した「cam2」で403エラーが出てしまいます。
ProxyPass /cam1 http://localhost:8081 ProxyPassReverse /cam1 http://localhost:8081 ProxyPass /cam2 http://localhost:8082 ProxyPassReverse /cam2 http://localhost:8082
apache再起動
systemctl restart httpd
これで例えば「https://sakue.com/cam1」へアクセスすると、ローカルの8081ポートで待ち受けているサーバが応答してコンテンツを表示します。
コメントフォーム