JavaScript と Cookie の有効・無効を判定する

Web アプリケーションで、JavaScriptCookie を使っているところは多いと思う。しかし、この 2 つは設定で無効にできるし、そもそも対応してないブラウザもある。そういう場合でもある程度動くようにするのがあるべき姿だが、どうしても必要な場合には、せめて事前にチェックをして、「この Web アプリケーションを使うには JavaScriptCookie が必要です」みたいなメッセージを出すべきだろう。
では、有効になってるかどうかは、どうすれば判定できるのか。


先日の日記で、browscap.ini ファイルを利用してブラウザの機能や OS バージョンを調べるコンポーネントについて書いたけど、これだけでは「いま設定がどうなっているか」はわからない。
さて、どうするか。

JavaScript 判定

2 種類の方法でリダイレクトを記述し、どちらが使われるかを見る。

<html>
<head>
<title>設定チェック</title>
<script language="JavaScript">
<!--
location.replace("check2.asp?js=1");
//-->
</script>
<meta http-equiv="Refresh" content="0; URL=check2.asp?js=0">
</head>

<body>
</body>
</html>

この例ではリダイレクト先 URL のパラメータだけ変えているが、もちろんファイルを変えてもよい。……と書いたところで、「クライアントによって動かなかったりしないかな」と不安になったのだが、下記のサイトでほぼ同内容のスクリプトを発見。IE、NN は OK だそうだ。

JavaScriptのオン/オフ状態に応じて表示するページを変える
http://www.openspc2.org/reibun/javascript/browser/011/

Refresh が使えないブラウザにも対応する場合は、body 要素内に説明を記述する必要があるだろう。よく見るのは「ページが自動的に切り替わらない場合は、ここをクリックしてください」ってやつ。
(17:33 追記: meta 要素のところ、"URL=" が抜けていたので追加。なお、Refresh も設定で無効にできるようだ。http://altba.com/bakera/hatomaru.aspx/ebi/topic/230 を参照のこと)
ちなみに、ネットで検索すると、

<html>
<head>
<title>設定チェック</title>
<script language="JavaScript">
<!--
function jump() {
   location.replace("check2.asp?js=1");
}
//-->
</script>
<noscript>
<meta http-equiv="Refresh" content="0; check2.asp?js=0">
</noscript>
</head>

<body onload="jump()">
</body>
</html>

という案もあるようだ。ただし、JavaScript に対応しているブラウザの中で、設定で無効にしている場合にも noscript 内を読み飛ばすのがあった気がする (うろ覚え)。また、HTML の仕様に従うと head 要素内に noscript 要素を置くことはできないので、これで動くブラウザがどれだけあるかとか、今後コンテンツ側を XHTML 等に変更しても動くのかとか、無駄な心配を抱え込むことになりそう。

Cookie 判定

実際に発行し、別のページに移動した時に Cookie がついてくるかを見ればいい。その応用で、Cookie でセッションを実現している場合は、セッションで値を保持できるかを見る方法がある。ブラウザに保持できる Cookie のサイズには制限があるので、既に使っている Cookie があれば、使った方がいい。作るのも楽だし。
ASP の場合、最初のページに

Session("CookieCheck") = "1"

とし、別ページにリダイレクトして

Dim gblnCookieEnabled

If Session("CookieCheck") = "1" Then
	gblnCookieEnabled = True
Else
	gblnCookieEnabled = False
End If
Session.Contents.Remove "CookieCheck"

ってな感じでチェックする。
ちなみに、ASP では、global.asa にイベントハンドラ Session_OnStart を記述できるが、今回の場合、ここで Session("CookieCheck") = "1" をしてもダメ。なぜなら、Cookie を無効にしている場合でも、2 ページ目にアクセスした際に IIS がセッションを作ってしまう。そのため、その後 Session("CookieCheck") を確認すると、"1" が取れてしまう。

組み合わせる

上記の 2 つを組み合わせてみる。JavaScriptCookie が両方有効になっていれば、index.asp→index2.asp→login.asp という順番でリダイレクトされ、ログイン画面 (login.asp) が表示される、という場合で考えてみる。
まず、index.asp

<%
Session("CookieCheck") = "1"
%>
<html>
<head>
<title>index1.asp</title>
<script language="JavaScript">
<!--
location.replace("index2.asp?js=1");
//-->
</script>
<meta http-equiv="refresh" content="0; index2.asp?js=0">
</head>

<body>
</body>
</html>

続いて、index2.asp

<%
gblnJSEnabled     = (Request.QueryString("js") = "1")
gblnCookieEnabled = (Session("CookieCheck")    = "1")
gblnReady = gblnJSEnabled And gblnCookieEnabled

Session.Contents.Remove "CookieCheck"

If gblnReady Then
	Response.Redirect "login.asp"
Else
%>
<html>
<head>
<title>index2.asp</title>
</head>

<body>
<ul>
<%
If Not gblnCookieEnabled Then
   %><li>Cookie無効</li><%
End If
If Not gblnJSEnabled Then
   %><li>JavaScript無効</li><%
End If
%>
</body>
</html>
<%
End If
%>

これを変形すれば、正常時の遷移が index.asp→login.asp で、JavaScriptCookie が使えないときは login.asp から failure.asp ページにリダイレクト、というかたちも作れる。