URLのリライトツールを自作してみよう(後編)
この記事は前後編の2回に分けてお届けしている。被リンクの処理について解説した前回に続いて、今回はコンテンツの表示と複製コンテンツの問題についてお伝えしよう。
コンテンツの表示
サイト内のリンクでも、検索エンジン結果ページのリンクでも、または外部サイトから張られているリンクでもいいけど、誰かが、/TravelSpecials/Hawaii-Maui/TheFairmontKeaLaniMaui.htm
へのリンクをクリックしたとする。すると、そんな名前のページは(もちろん、フォルダだって!)ないんだから、ここでちょっとした仕掛けが必要になる。(まだ作成していなければ)専用の404エラーハンドラを作成して、そこでこうしたリクエストを探し出し、それを「/Package.asp」というページに引き渡してコンテンツを表示できるようにしなければならない。
以下に例を示そう。
On Error Resume Next
Dim iPos, sPageHit, cnList, cmdList, & _
sUserID, rsUserWebPage, sGuestPassword, chTmpRegTypes
PageHit = Trim(Request.QueryString)
iPos = InStr (12, sPageHit, "/", 1)
sPageHit = Right (sPageHit, Len(sPageHit) - iPos)
sPageHit = LCase (sPageHit)
Dim sPageLeaf, iDomainEnd
sPageLeaf = LCase (Trim(Request.QueryString))
iDomainEnd = InStr (sPageLeaf, "thebigday.com")
If (iDomainEnd > 0) Then
sPageLeaf = Mid (sPageLeaf, iDomainEnd + Len (sThisPageDomain))
End If
'変換する必要のある静的ページかどうか調べる:
If (Left(sPageLeaf, 8) = "/travelspecials/") Then
Server.Transfer "/Package.asp"
End If
...
もしこれが、自分の作った魔法の仮想ページのいずれかに該当しなかった場合、このアルゴリズムでは実際に404ページを表示するようになっている。Server.Transfer
はページのコンテンツ生成を/Package.asp
に任せるけれども、ユーザーのブラウザにはわかりやすいURLが表示されたままで、ブラウザは「200 OK」というHTTPレスポンスコードを受け取るという点に留意してほしい。
/Package.asp
では、次のような処理が必要となる。
- 大分類名、小分類名、ホテル名を取り出す。
- それぞれをデータベースで参照して、対応するパラメータを取得する。
- 大分類、小分類、ホテルに関して必要なデータをすべてデータベースから取り出し、コンテンツをページに表示する。
次の疑問:/Package.asp
の内部では、読みやすいURLに301リダイレクトすべきなのか、それとも404ハンドラで転送されてきただけなのか、どうやって判別するんだろう? これは実は簡単なんだ。
404ハンドラの取り扱い
とにかくIISの404ハンドラは、クエリ文字列の中にリクエストされた元のURLを持っており、その先頭に「404」というコードが加わる。この例で言うと、クエリ文字列全体は次のようになる。
だから
を探すだけでいいんだ。やり方は以下の通り。
sFullQueryString = LCase (Request.QueryString)
If (Len (sFullQueryString) > 8) Then
If (Left (sFullQueryString, 8) = "404;http") Then
Call ExtractResortParms (sFullQueryString)
End If
End If
ここで出てきた「ExtractResortParms()」関数は、クエリストリングを解析して、大分類名、小分類名、ホテル名を取り出し、それらをデータベースから探し出す。
僕のExtractResortParms()関数がどんなふうになってるか実際に見たいという人がいたら、メールしてね。凄いっていうほどのものでもないけど、「Mid()」「Left()」「InStr()」なんていう関数をいろいろ使っているから、まあおもしろいと思う。
ここで、URL内のホテル名などはデータベースの内容と必ずしも正確には一致しない、ということを思い出してほしい。スペースや区切り記号が除去されるため、「Fairmont Kea Lani」は「FairmontKeaLani」となっている。だから、名前をインデックスとしてデータベースを参照することはできない。では、どうするか。可能性のある名前をすべてレコードセットに抜き出し、そのレコードセット内の名前それぞれを整形関数に通して、それがURLから取り出した名前と一致するかどうかを確認をするんだ。
もし、抜き出したレコードセットが(100件を超えるなど)非常に大きい場合、パフォーマンスをもう少し改善したいところだが、僕の場合、大分類と小分類はいずれも種類が少なかったから、その点については心配していない。ただしホテル名については、僕はまず先に、大分類名と小分類名を取り出してから、それに一致するリゾート名の一覧を抜き出すようにしている。こうすると、リストがぐっと短くなるんだ。
それから、パフォーマンスを大きく向上させる非常にうまいやり方がもう1つある。それは、データベースのテーブルに、「整形後」の名前を入れるフィールドを追加してしまうことだ。そして、コンテンツ要素を追加/編集するコンテンツ管理ページで整形関数を呼び出し、新しく生成された整形後の名前の列をインデックスに指定すればいい。
301リダイレクト
クエリ文字列の先頭に「404;http」が見つからなかった場合、多分URLにパラメータを含むページにリンクしているので、URLの読みやすいページに301リダイレクトしなければならない。「でも、ちゃんと変数があるんだから、単純にコンテンツを調べて、それを表示させればいいのでは?」という質問が出そうだ。でも、旧URLのリンクジュースをすべて、新しい判読可能なURLに飛ばしたいのだろう? そこで、クエリ文字列から変数を抜き出すのがいいね。
たとえば、次のようなリンクがあったとする。
そしてこれを、前に君が書いたすばらしい関数を使って、読みやすいURLにリダイレクトする。
Response.Status = "301 Moved Permanently"
Response.AddHeader "Location", MakeFancySchmancyUrl (nDestID, nSubdestID, nResortID)
リンクジュースをしっかりゲット
ときどき製品名を変えることがあるなら、あちこちでリンクジュースを損している可能性がある。たとえば、Princeville Resortは今、The St. Regis Resort, Princevilleに名前が変わっている。そして誰かがちょっと前に、以下のURLにリンクを張っていたとする。
もちろんこのままだと、「整形」して「PrincevilleResort」になる名前のホテルなんてもうないから、ユーザーに正真正銘の404ページを返すことになり、リンクジュースも得られない。
この問題を解決するには2つの方法がある(どちらを選ぶかは、名称変更の頻度による)。
名前の変更が滅多にない場合、その都度、手作業で404ハンドラに301リダイレクトを追加すればいい。
ホテル名の変更履歴を記録するテーブルを作成して、コンテンツ管理プログラムがホテル名を変更するたびに、このテーブルにそのレコードを付け加えるようにすることもできる。こうすれば、ホテルのページを表示するプログラムが一致する名前が見つけられなくても、リクエストのあった整形後の名前を、このテーブルで参照できる。
複製コンテンツの問題
自分の顧客がどのように買い物するか調べたことがある人なら、自分にとって最も合理的で便利な製品分類の方法が、顧客の製品に対する考え方と必ずしも一致しないことに気づいているだろう。そしてすでに、製品を何通りもの分類方法でグループ化しているだろうから、ある製品のページが複数の異なるURLで表示されることになる。
僕のTheBigDayの場合、ホテルを所在地だけで分類しているわけではなく、体験の種類やブランドでもグループ分けしている。こういった場合、検索エンジンに、リライトしたURLのうち1つだけが「メイン」のもので、あとはまったく同じページであることを伝えなければならない。さてここでいよいよ「rel="canonical"」という新しい仕掛けの登場だ。僕の場合、カテゴリ(「オールインクルーシブ」「スパ」「ラグジュアリ・ホテル」など)を仮の所在地としてコード化しているので、そのリゾートに割り当てられている本来の所在地IDを調べて、URLを生成しなければならない。
<link rel="canonical" href="http://www.thebigday.com<%=MakeFancySchmancyUrl (nDestID, nSubdestID, nResortID)%>">
まとめ
こうして書いてくると、すごくたくさん作業があるように見えるけど、冗談抜きで、1日で終わらないなんてことはないはず。行き詰ったりわからなくなったりしたときに質問できる僕のような人間がいるれば、なおさらだ(^-^)。
ソーシャルもやってます!