意図通りのURLにユーザーを誘導したい

HTMLでは

<link rel="canonical">

を書いてあげればよい。

JavaScriptでは

location.host

を見て意図通りの URL でなかったら location を書き換えてあげればよい。

サーバ側アプリでは

基本的には HTTP_HOST を見る。ところが構成によってここで取得できる値は変わる。1

例えば Heroku の場合はもともと *.herokuapp.com の名前を持っている。これに DNS の ANAME や CNAME で hostname を設定し、これをユーザーに見せる URL として設定することになるのだが、ここに CDN が加わると設定方法にバリエーションができる。

※ 以下はアプリケーションサーバが Heroku にある前提で書いていくが、別にどんなサーバでも構わない。単にデフォルトの名前が分かりやすく決まっているので参考に挙げやすいだけである。

a) CDN側にだけDNSを設定する

  1. Heroku 側では別な endpoint を定義せず
  2. CDN 側で endpoint を定義する(例えば example.com で Origin を *.herokuapp.com に)

形になっている場合、当然だが Heroku 側で拾える HTTP_HOST はデフォルトのものだけになる。

+-----+
| DNS |
+-----+
   ↓
+-----+    +-----+
| CDN | → | App |
+-----+    +-----+

App で拾えるのはデフォルトの *.herokuapp.com だけ。なぜなから CDN から *.herokuapp.com でアクセスされるから。

これの対処は後述。

b) CDNにもAppにもDNSを設定する

      +-----+
      | DNS |
      +-----+
         ↓
   +----------+
  ↓          ↓
+-----+    +-----+
| CDN | → | App |
+-----+    +-----+

App の endpoint も DNS で設定して

  • example.com ( Heroku )
  • cdn.example.com ( CDN )

のように設定できるなら App 側で Canonical(この場合は *.herokuapp.com ではなく example.com)かどうかを HTTP_HOST で取得することができる。

CDN経由かどうか

ということで今度は CDN 経由かどうかを知りたい場合。上の a) のパターン。

  • Via ヘッダを見れば経由サーバがあるかどうかは分かる
  • Heroku のようなマルチテナント PaaS や Load Balancer 経由のアクセスの場合は常に Via 値があるので、意図したサーバを経由したかどうかは「Viaヘッダがあるかどうか」だけでは判別できない
  • CDN や Load Balancer 経由かどうかは「Via ヘッダに入る文字列」での判別になる
    • 多段の場合は複数の情報が文字列で入る

ということで例えば Rack であれば

env['HTTP_VIA'].include?(特徴的な文字列)

で判別できる。

  1. Rails 4 までだと直接 HTTP_HOST を見ずに request.host を使えばいいと思う。5 以降はこのメソッドなくなったそうなんだけど、使ってないので分からない。 

More