パスワードを忘れた? アカウント作成
1926134 journal
日記

Torisugariの日記: ウェブのリダイレクトについて (後)

日記 by Torisugari

2.3 meta要素のrefresh指示子によるリダイレクト

これは前項の「HTTPのRefreshヘッダによるリダイレクト」をHTMLだけで実現するための機能であり、長らく独自仕様でしたが、HTML5で標準化されました。

meta http-equiv=refresh – “refresh” pragma directive

全ての主要ブラウザが既に実装しており、サーバー側の設定ができない場面や時間差をつけてリダイレクトしたい場合に多用されています。JavaScriptを切っていても動作するので、特に理由がない場合は、300番台のリダイレクトかこれを使うのが望ましいでしょう。

meta要素によるリダイレクトでは、仕様上、セッション履歴(「戻る」ボタンで戻れる履歴)に痕跡が残りません。Geckoの場合、私の記憶が確かなら、かなり長時間(300秒以上?)の時間指定で履歴に残すという挙動だったと思いますが、もとよりリダイレクトが目的なら、そんな時間指定をすべきではないでしょう。

2.4 JavaScriptによるリダイレクト

JavaScriptでリダイレクトを行うのは外道とまでは言わないものの、決して王道といえるようなものではありません。JavaScriptでページ遷移が可能なのは、複雑な条件下でそれを必要とする場合があるからであり、決してリダイレクトのように単純な条件でのページ遷移をするためではないからです。

しかし、理想は得てして現実の前に散る運命です。実際のところ、HTMLはJavaScriptによるリダイレクトをある程度想定しています。私が前項で薦めたmeta要素も標準準拠ではないのとアクセシビリティの観点から、悪し様に言われた時期がありました。例えば、2007年の啓蒙記事「Don't break the back button!」などがそうです。まあ、今でもベストとは言いがたい側面がありますが、どこかで利便性とのバランスをとる必要があります。

2.4.1 Locationオブジェクトによるリダイレクト

JavaScriptでリダイレクトする場合、最もよく使われるのがLocationオブジェクトでしょう。ここで問題になるのはどのタイミングでリダイレクトを行うか、です。HTML5に準拠している場合、文書のloadイベントの前後で挙動が変わります。具体的に言うと、例えば、scriptタグの中に直接書く場合、

<script>
  window.location.href = "http://www.example.com";
</script>

<script>
  window.location.replace("http://www.example.com");
</script>

は同じ振る舞いをし、いずれもリダイレクト元がセッション履歴に残りません。

一方、イベントハンドラから呼ばれる場合、

<body onload="setTimeout(function(){window.location.href = 'http://www.example.com/';}, 0);">

<body onload="setTimeout(function(){window.location.replace('http://www.example.com');}, 0);">

を比べると、後者は同様にリダイレクト元がセッション履歴に残らないのに対して、前者はリダイレクト元がセッション履歴に残ります。これは、Location::hrefへの代入、あるいはLocation::assign()の呼び出しが文書の読み込み完了より早いかどうかで、「リダイレクトのような挙動」なのか、「リンクを踏んだような挙動」なのかを判断すべき、とされているからです。

リダイレクトだけが目的なら、曖昧さを消すためにもLocation::replace()を使う方が良いでしょう。

2.4.2 DOMイベント系によるリダイレクト

説明すると長くなるので、実際に動くコードを書いてみました。

HTMLFormElement::submit()で、リダイレクトする例:

<form id="foo" action="http://www.example.com/" method="GET"></form>
<script>
  document.getElementById("foo").submit();
</script>

HTMLElement::click()で、リダイレクトする例:

<a id="foo" href="http://www.example.com/">foo</a>
<script>
  document.getElementById("foo").click();
</script>

もともと、DOM2でのclick()はinput要素にしか使えませんでしたが、HTML5では普通のリンクにも使えまます。HTMLDocument::createEvent()でclickイベントを作成すれば、HTMLElement::click()と同じ効果ですから、リダイレクトも実行できます。正直な話、わざわざリダイレクトをするためにa要素を用いる理由は見当たりませんが、簡単に書けるのも確かです。ただし、リダイレクト元がセッション履歴に残ります。

一方、form要素を使ったリダイレクトは、a要素の場合とは違って、ある程度の実用性があります。新たにPOSTメソッドでリダイレクトするのは、HTMLFormElement::submit()HTMLElement::input()などをform要素に作用させてリクエストを送るしかないからです。しかも、リダイレクトですから、XMLHttpRequestとは違ってクロスドメインの制限を受けることはありません。ちなみに、「クロスサイトリクエストフォージェリ(CSRF)」という攻撃は、端的に言ってこのリダイレクトのことを指します。

2.4.3 Historyオブジェクトによるリダイレクト

History::back()History::forward()はリダイレクトの一種です。ただし、用途は明確なので大きな問題にはなりにくいでしょう。

HTML5で加わったHistoryオブジェクトの新機能にHistory::pushState()History::replaceState()があり、これらを使うと文書(document)を遷移させずに場所(URL)を移動させることが出来ます。ですから、最初に定義した「リダイレクト」の範囲に収まるかどうかは微妙なところですが、Location::reload()などと組み合わせると紛う方なきリダイレクトになります。ただし、あえてこの方法でリダイレクトする意義はないでしょう。また、これらはドメインをまたいでURLを設定できるわけではないので、使える局面は限られています。

2.4.4 window.open()によるリダイレクト

例えば、

<script>window.open("http://www.example.com/", "_self");</script>

でリダイレクトさせることができます。ただし、これもリダイレクト元がセッション履歴に残ります。

JavaScriptに関しては長くなったので、まとめておくと、実用上は、ほぼ、Location::replace()HTMLFormElement::submit()の二択だと言えます。

2.5 プラグインによるリダイレクト

私の知る限り、ブラウザの機能を使うリダイレクトは以上4つのいずれかで、残るはブラウザに後付けされた機能ということになります。しかし、例えばFirefoxやChromeの拡張機能としてリダイレクトする機能を追加することは可能ですが、それではあまりも状況が特殊すぎるので、一般論として展開することはできません。ウェブ開発者にとっては頼りない話ですし、ユーザーにとってみれば気に留める必要もありません。

ただし、多くの人がブラウザにインストールしているソフトがあれば話は変わってきます。つまりFlashのことですね。

そもそも、NPAPIにはNPN_GetURL()という関数があり、この機能はほぼ、window.open()に相当するので、前述のようにリダイレクトが可能です。PPAPIにもNavigateToURL()という名前で備わっており、FlashのActionScriptでは、navigateToURL()によりラッピングされています。

また、ActiveXを使っていたり、NPRUNTIME以降の世代のプラグインはそのウィンドウのグローバルスコープからJavaScriptを実行可能なので、Flashの場合、2.4節で説明したJavaScriptのリダイレクトについては、ほぼそのまま当てはまります。ただ、ユーザー側の視点から考えると、スクリプトがテキストファイルとして人間が読める形で提供されているとは限らないので、その点には特に気をつける必要があるかもしれません。

3. リダイレクトの倫理

リダイレクトは、その本来の用途とはズレた目的に使われることが多い機能です。それは、あるいは検索エンジンによるトラッキングであったり、あるいは広告業者による広告への誘導であったりします。私は、こういった目的に正当性がない、とまでは言いたくありません。しかし、ほとんどの場合、ユーザーの断りなしに行われている点については議論の余地があるでしょう。

私はこれらの倫理的問題を直接解決するつもりがないので、問題提起に留めておきますが、リダイレクトの支持率(あるいは不支持率)といったようなものは常に気にしておくべきだと思います。

ところで、私はリダイレクトのやり方はこれで全部だと思っているのですが、一字千金を気取るつもりもないので、抜けている部分があれば、どこかにコピペする前に直しておいてください。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
typodupeerror

物事のやり方は一つではない -- Perlな人

読み込み中...