JavaScriptにおけるURLエンコードの処理
このメモは、JavaScriptでクッキーを処理する場合のポイントをお示しし、URLエンコードに関わるトラブルを回避していただくことを目的にしています。お急ぎの方は3章と4章を飛ばして読んで頂いて構いません。なおこのメモはなるべくIEでご覧下さい。 目次 3. 3 JavaScriptにおけるescape()とunescape()関数 4. 4 JavaScriptにおけるencodeURI、decodeURI、encodeURIComponent、decodeURIComponent |
HTMLテキスト以外にウェブ・サーバがブラウザに情報を渡す手段は、HTTP応答メッセージのヘッダ部分にその情報をセットすることです(ボディ部分には通常HTMLテキストが入ります)。サーバ側からはクッキー設定のヘッダ行や自分で作った特別なヘッダ行に情報をセットできます。これらは(名前、値)のペアの形式をとります。
HTMLテキスト外で渡される情報は、ブラウザ画面に表示されないので、表示の目的以外のセッション管理などに使われます。サーブレットにおけるクッキーによるセッション維持のメカニズムは、まさしくこの特性を利用したものです。セッション以外にもクライアントとの各種管理情報(ブラウザのタイプやバージョン、ユーザ情報など)、暗号化のための情報(鍵や方式など)の交信といった応用も考えられます。また送ったクッキーはクライアントに蓄積されるので、繰り返し表示や画面に共通の情報を最初にクッキーで送ってしまうことも可能です。また、フォームに表示しないで必要な情報をサーバに返すことも出来ます。
たとえばTomcatなどのサーブレット・エンジンがセッション維持に使っている(“jsessionid”, ID)の類のメカニズム以外に、もっと詳細にそのセッションの情報(ユーザの名前など)をクライアントで維持し、必要に応じこれを表示するなどが可能になります。
JavaScriptにおいては、HTTP応答メッセージのヘッダ行を直接取り出す機能は残念ながらありません。しかしながらWindow.document.cookieオブジェクトを使って、クッキーを介した情報のやり取りが可能です。しかしながら、後述のようにHTTPメッセージのヘッダ行はURLエンコードされねばなりません。ASCII文字セットだけで済む欧米と違って我々のように2バイトの文字セットを標準的に使う場合は、URLエンコードに注意しなければなりません。皆さんが悩みまた問題を起こしやすいのはこの点でしょう。
このメモは、JavaScriptでクッキーを処理する場合のポイントをお示しし、URLエンコードに関わるトラブルを回避していただくことを目的にしています。
クッキーとURLエンコーディングの基本的な知識が必要になりますので、最初にそのポイントを実例でお示しします。 |
通常cookieはアプリケーション・サーバがHTTP応答のパケットのヘッダ部分にセットしてブラウザに渡します。例えばIBMのサーブレット・エンジンは次のようなHTTPのヘッダ行をHTTP応答につけてセッション(サービスとクライアントとの対応の識別)の維持をとろうとしています。この例()ではsessionidという「名前」の変数とLV・・なる「値」の組を渡しています。
Set-Cookie:
sessionid=LV140HYAAAABZQ....;Path=/ |
このようにcookieはHTTPパケットのヘッダ行によって伝達されるので、2バイト文字や”;”や”=”などの危険な(プロトコル上意味を持つ)文字を含む「名前」や「値」を持つcookieをクライアントに渡すときは、危険なバイト文字を含まないようURLエンコードして、バイト列として伝達せねばなりません。
マルチバイト文字をサーブレット・エンジンは果たしてこれを認識して自動的にURLエンコードしてくれるのだろうか実験してみましょう。
次のサーブレットはネット上(http://ash.jp/java/hellocookie.htm)で公開されていたプログラムに一部手を加えたものです。このプログラムはサーブレットにおけるクッキー処理に関するヒントが入っていますので、ひととおり理解してください。
import
java.io.*; import
java.net.*; import
javax.servlet.*; import
javax.servlet.http.*; /**
クッキー読み書きサーブレット **/ public
class HelloCookie0 extends HttpServlet { public void doGet (HttpServletRequest
req, HttpServletResponse res) throws ServletException, IOException { PrintWriter out; Cookie[] cookies; Cookie cookie; // Cookieの取得 cookies =
req.getCookies(); cookie = null; if (cookies != null){ for(int i=0;
i < cookies.length; i++) {
cookie = cookies[i];
if (cookie.getName().equals("HelloCookie")) { break; } } }
res.setContentType("text/html; charset=Shift_JIS"); out = res.getWriter(); HttpSession session =
req.getSession(); // Sessionの取得と書き込み
session.setMaxInactiveInterval(600);
// 10分間有効 if (session.isNew())
{ // Cookieの書込み cookie = new
Cookie("HelloCookie", "Hello World!");
cookie.setMaxAge(60);
// 有効期間は1分で切れる res.addCookie(cookie);
out.println("<html><body>");
out.println("<h1>Write Cookie</h1>"); out.println("<p>リロードしてください。</p>");
out.println("</body></html>"); } else { // Cookieの表示
out.println("<html><body>"); out.println("<h1>"); for(int i=0;
i < cookies.length; i++) {
cookie = cookies[i];
out.println(cookie.getName()+" : "+ new
String(cookie.getValue().getBytes("8859_1"),
"Shift_JIS"));
out.println("<BR>"); } out.println("</h1>");
out.println("<p>Cookieのサンプル(HelloCookie0.java)</p>");
out.println("</body></html>"); } } } |
このプログラムでcookie = new Cookie("HelloCookie", "Hello World!");という行の「値」の文字列に漢字や危険な文字を設定するとサーブレット・エンジンはどのような応答パケットを送信するか試してみましょう。
a) ”Hello 日本!”と変えてtelnetのソフトウエアでアクセスすると次のような結果が得られます。最初の2行(空白行も含む)はtelnetが送ったHTTP要求メッセージです。それ以降がサーブレット・エンジン(ここではTomcat)が返したHTTP応答メッセージです。前半がヘッダ部分、最後の4行がボディ部分です。さてHTTP応答のヘッダ部分を見ると、Set-Cookieなるヘッダ行が2行存在することがお分かりでしょう。最初はサーブレットが作成したもので、後のはサーブレット・エンジンがセッション維持の為に作成したものです。従って、ブラウザにしてみると、2つのクッキーが渡されたということになります。ブラウザ側でこれらのクッキーに何も変更を加えなければ、サブミット・ボタンなどでこのURLを再度アクセスしたときには、これらのクッキーは有効期限が切れていなければそのままサーバに返されます。
GET
/examples/servlet/HelloCookie0 HTTP/1.0 HTTP/1.1
200 OK Content-Type:
text/html; charset=Shift_JIS Connection:
close Date:
Wed, 30 Oct 2002 03:45:24 GMT Server:
Apache Tomcat/4.0.4-b3 (HTTP/1.1 Connector) Set-Cookie:
HelloCookie=Hello 日本!;Expires=Wed, 30-Oct-2002 03:50:25 GMT Set-Cookie:
JSESSIONID=BAFB93DD6C7848751C369747B316DB6C;Path=/examples <html><body> <h1>Write
Cookie</h1> <p>リロードしてください。</p> </body></html> |
b) さてこのHTTP応答メッセージをみると、telnetの対応文字セットをShift_JISとしたので、“Hello 日本!”の部分は文字化けを起こさないで正しく読み出されています。また、IE(v6)でhttp://localhost:8080/examples/servlet/HelloCookie0とアクセスし、皆さんのPCのC:\WINDOWS\Cookiesを調べると、このクッキーが文字化けしないで受理されているのが確認できるでしょう。でも、実はこれは、たまたまうまくいったというだけなのです。”日本”という文字はShift_JISとしてヘッダに入っているのですが、このバイト列のどのバイトもASCIIの「危険な文字」に落ちていないからです。更に、この実験ではローカルのホストを使っており、ネットワークを介してはいません。ネットワークのノードによっては(古いシステムですが)7ビットしか伝送されず、最上位の1ビット(MSB)は誤り検出や同期などの目的に使われているものもあります。そのようなノードをこのHTTPメッセージが通過すると、当然文字化けを生じてしまいます。
c) 危険な文字を含む文字列がクッキーの「値」の場所にセットされたらどうなるでしょうか?クッキーの「名前」に危険な1バイト文字が含まれているとサーブレット・エンジンは例外を生じるよう規定されているのですが、「値」にはそのような制約がどういう訳だか規定されていません。試しに” AAA ;B%BB”とスペースとセミコロンを含む文字を出力してみよう。telnetでこのサーブレットを呼び出して見ると次のようなHTTP応答パケットを観察することができます。
HTTP/1.1
200 OK Content-Type:
text/html; charset=Shift_JIS Connection:
close Date:
Tue, 22 Oct 2002 04:39:25 GMT Server:
Apache Tomcat/4.0.4-b3 (HTTP/1.1 Connector) Set-Cookie:
HelloCookie=Hello AAA;B%BB;Expires=Tue, 22-Oct-2002 04:44:26 GMT 以下省略 |
これをブラウザ(IE6)はどのように取り込んだかをExplorerで見るとC:\WINDOWS\Cookiesのディレクトリに記録されているファイルは次のようなテキストになっています。つまりスペースは受け付けたがセミコロン以降はクッキーとしては受け付けてはいないのです。セミコロンはインターネットの世界では「区切り文字」なのです。
HelloCookie AAA localhost/examples/servlet/ 1024 1088345728 29522332 2383813024 29522331 * |
次の章で詳しく説明しますが、URLエンコーディングはMSBが1のバイトや、インターネット上で特別の意味を持つ7ビットASCII文字を、7ビットASCII文字を使って混乱させないで送るための仕組みなのです。
これまでの実験からお分かりのように、クッキーの送信にあたっては名前、値ともURLエンコードして送ることが推奨されます。これはNetScape社の解説書でも推奨されていることであります。なおサーブレット・エンジンがセッション維持の為にcookieをセットするときはURLエンコードしてはいない、というかURLエンコードの必要のない文字しか使っていません(URL変換しても何の変化も生じません)。telnetなどで検査しやすい(バイトのままでも「名前」がそのまま読める)よう、「名前」はURLエンコードに引っかからない英数の文字列にすることがトラブル防止になるでしょう。
さて、次のように名前と値双方をJavaのURLEncoderでエンコードして作ったクッキーはどのようにブラウザが処理するか調べてみましょう。
String
namestring = "内閣総理大臣"; String
valuestring = "小泉純一郎"; namestring =
URLEncoder.encode(namestring, "Shift_JIS"); valuestring =
URLEncoder.encode(valuestring, "Shift_JIS"); cookie = new Cookie(namestring, valuestring); |
そうすると、c:\windows\cookiesのファイルを調べてみると次のようにブラウザはURLエンコードされた文字列をそのまま受け取っているだけだと言うことがわかります。これを元に戻すのはプログラマの責任という訳です。
%93%E0%8A%74%91%8D%97%9D%91%E5%90%62 %8F%AC%90%F2%8F%83%88%EA%98%59 localhost/examples/servlet/ 1024 3287822464 29522316 294622464 29522316 * |
つまりNetscapeの考え方は、「クッキーは1バイト文字で、且つ安全な文字で構成された文字列が名前と値のペアとして存在していることを前提としている。そうでない文字列をそのような制約にしたがって変換して使うのはプログラマの責任である」というものでしょう。
どのようなバイト列でも7ビットだけのASCII文字を使ってインターネットの網を通過させるための仕組みとしてのURLエンコーディング、あるいはその逆のURLデコーディングについてもう少し詳細に理解することにします。 |
メール(SMTP)やHTTPなどのパケットは、ヘッダ部に宛先やその他メッセージの制御に関わる情報が載せられます。このヘッダは途中の(ヘッダが解釈される)ゲートウエーを幾つか中継され、端から端のノードに伝達されるので、これらのノードに理解できるコードと文字で表現されなければなりません。ヘッダ部に日本語のような2バイトの文字が入ると、ノードはこれを1バイトずつ解釈しようとします。そのときにそのバイトのどれかがノードにとって特別の意味を持つバイトであったら、正しい結果が得られなくなってしまいます。更にネットワークによっては各バイトの一番上のビット(MSB)を欠落させる伝送ノードが存在します。従ってどのような文字であってもそのような制約のなかで安全に且つ透過的に伝送されることが必要になります。具体的には7ビットで且つ「安全な」ASCII(American Standard Code for Information Interchange)文字セットからなる文字列に変換してインターネットを通すということです。そのような仕組みとしてURLエンコードが考えられました。URLエンコードというのは、もともとヘッダ部のURL部分に2バイト文字や制御文字と紛らわしい文字が入るのを防止するために考えられたからそう呼ばれています。しかし送られる情報をすべて「見える」文字列に変換するのは都合が良いことが多く、メッセージのボディ部分の伝達にも使われます。ボディ部分の変換にはもうひとつMIME(Multi-Purpose Internet Mail Extensions)のエンコーディングがあります。これは2バイトのバイナリ・データを3バイトの7ビットASCII文字に変換するもので、マルチメディア情報の転送に使われます。
URLエンコードの手順は以下のようです。
@ 日本語のように2バイトの文字は1バイト毎にとりだしてASCII文字とみなして以下の変換を行う。 A 名前と値にある「安全でない」文字は"%xx"というエスケープ文字列に変換する。"xx"はその文字のASCII値を16進表示したものである。「安全でない」文字には=, &, %, +やプリントできない文字,MSB(最上位ビット)が1の文字を含む。 B 全てのASCIIのスペース文字を+に変換する。 C 名前と値を=と&でつないでひとつの文字列にする。例えばname1=value1&name2=value2&name3=value3 |
この文字列がPOST要求メッセージのボディ部分、あるいはGET要求のクエリ文字列、あるいはクッキーのヘッダ行としてはめ込まれるのです。
いよいよクライアント(ブラウザ)のほうに話を移しましょう。JavaScriptでは当初はescape()とunescape()のグローバル関数がそのような目的で使われることがありました。しかしこれらの関数は完全なURLエンコード対応でない上に、その関数の定義が途中で変わってしまい、お勧めできません。 |
そうするとJavaScriptでクッキーを読み出すとき、URLエンコードされたクッキーをどの文字セットだと理解してデコードするのでしょうか?JavaにおいてもURLEncoderとURLDecoderの二つのクラスにおいて文字セット(しかもW3Cが勧告しているからといってUTF-8を推奨!)を指定するようになったのが最近のこと(j2sdk1.4から)なのです。
JavaScriptの言語仕様(escape/unescape)にはそのような機能が存在しないのが混乱のもとになっているようです。例えばescape()メソッドはNN(Netscape Navigator)はShift_JISのコードをURLエンコードもどきで、IE(Internet Explorer)はユニコード表記(エスケープ・シーケンスであってUTFではない!)を返してしまうのです。逆操作のescape()メソッドもこれに対応します。ところが問題を更に複雑にしているのが、IEのescape()関数は通常のUTF-16のURLエンコード(例えばj2sdk1.4のURLEncoder.encode(str, “UTF-16”);)とは全く異なる単なるユニコード表記の文字列をつくりだす、ということなのです。例えば次のようなhtmファイルをIEで開くと、
<HTML> <HEAD> <TITLE>JavaScript
escape()/unescape() functionarity test</TITLE> <META
HTTP-EQUIV="content-type" CONTENT="text/html;
charset=SHIFT_JIS"> </TITLE> <BODY> <PRE> JavaScriptにおけるescape関数のブラウザによる相違をチェックする <SCRIPT
LANGUAGE="JavaScript"> s="内閣総理大臣=小泉純一郎"; document.writeln("original
string : "+s); s=escape(s); document.writeln("escaped
string : "+s); s=unescape(s); document.writeln("unescaped
string : "+s); </SCRIPT> </PRE> </BODY> </HTML> |
JavaScriptにおけるescape関数のブラウザによる相違をチェックする original string : 内閣総理大臣=小泉純一郎 escaped string : %u5185%u95A3%u7DCF%u7406%u5927%u81E3%3D%u5C0F%u6CC9%u7D14%u4E00%u90CE unescaped string : 内閣総理大臣=小泉純一郎 |
つまり%u・・・・なるユニコードの16進表記を返していることがお分かりでしょう。
次のように、IEがunescape()関数を使って読み出せないかとURLEncoder.encode()メソッドを使ってサーバ側で、cookieをセットしたとしましょう。
import
java.io.*; import
java.net.*; import
javax.servlet.*; import
javax.servlet.http.*; /**
クッキー読み書きサーブレット
**/ public
class HelloCookie extends HttpServlet { public void doGet (HttpServletRequest
req, HttpServletResponse res) throws ServletException, IOException { PrintWriter out; Cookie[] cookies; Cookie cookie; String urlencoding =
"UTF-16"; //必要に応じ"Shift_JIS"や”UTF-8”などを試す // Cookieの取得 cookies =
req.getCookies(); cookie = null; if (cookies != null){ for(int i=0;
i < cookies.length; i++) {
cookie = cookies[i];
if (cookie.getName().equals("HelloCookie")) { break; } } }
res.setContentType("text/html; charset=Shift_JIS"); out = res.getWriter(); if (cookie == null)
{ //
Cookieの書込み String namestring
= "内閣総理大臣"; String
valuestring = "小泉純一郎"; namestring =
URLEncoder.encode(namestring, urlencoding); valuestring =
URLEncoder.encode(valuestring, urlencoding); cookie = new
Cookie(namestring, valuestring); cookie.setMaxAge(300); // 有効期間は5分で切れる
res.addCookie(cookie);
out.println("<html><body>");
out.println("<h1>Write Cookie</h1>");
out.println("<P>");
out.println("<SCRIPT
LANGUAGE=\"JavaScript\">");
out.println("s=unescape(document.cookie);");
out.println("document.write(\"unescaped cookie :
\"+s);");
out.println("</SCRIPT>");
out.println("</P>"); out.println("<p>リロードしてください。</p>");
out.println("</body></html>"); } else { // Cookieの表示
out.println("<html><body>");
out.println("<h1>");
out.println(URLDecoder.decode(cookie.getValue(), urlencoding));
out.println("</h1>");
out.println("<p>Cookieのサンプル(HelloCookie.java)</p>");
out.println("</body></html>"); } } } |
このときtelnetでアクセスしてTomcatが送信するHTTP応答パケットのSet-Cookie行を調べると次のようになっています。
Set-Cookie:
%FE%FF%51%85%95%A3%7D%CF%74%06%59%27%81%E3=%FE%FF%5C%0F%6C%C9%7D %14%4E%00%90%CE;Expires=Wed,
23-Oct-2002 04:33:23 GMT |
つまり「内閣総理大臣」の文字列は%FE%FF%51%85%95%A3%7D%CF%74%06%59%27%81%E3に、「小泉純一郎」の文字列は%FE%FF%5C%0F%6C%C9%7D%14%4E%00%90%CEに変換されています。FEFFなる文字列はこれがBOM(バイト順マーク)で、ビッグエンディアンであることを意味します。これが正式のUTF-16コード表示なのです。「内閣総理大臣=小泉純一郎」という文字列の場合は次のように変換されます。
%FE%FF%51%85%95%A3%7D%CF%74%06%59%27%81%E3%00%3D%5C%0F%6C%C9%7D%14%4E%00%90%CE |
当然のことながらこのサーブレットの出力をIEの unescape()関数は正しく受け付けてはくれません。
IEが作り出す「内閣総理大臣=小泉純一郎」のエンコーディングはさきほど示したように単なるユニコード表記の
%u5185%u95A3%u7DCF%u7406%u5927%u81E3%3D%u5C0F%u6CC9%u7D14%u4E00%u90CE |
であって、これとは全く異なっています。おまけに”=”という文字はユニコード表示されないで単なる%3DというASCII文字として処理されてしまっています。どうして%u003Dとしないのでしょうか。ECMA-262に準拠したもののようですが、困ったものです。したがって「IEの場合は怪しげなescape()とunescape()関数は使わないほうが良い」というのが結論です。
ちなみに先ほどのサーブレットで String urlencoding = "Shift_JIS";と変更して、これをNNで呼び出すと次のように正常に表示されます。
但しNNではShift_JISのURLエンコードを使っていれば問題がないかというと残念ながらそうではありません。例えば「内閣総理大臣 小泉純一郎」と間に半角スペース文字が入っているとNNは「内閣総理大臣+小泉純一郎」とプラス記号に変えてしままいます。これはURLエンコードの解釈の相違によるもので、j2sdk1.4ではスペースは”+”文字に変換するのに、NNのescape()関数の場合はスペースを%20に変換します。細かいことですがj2sdk1.4では総て統一して%nnの形式で変換するのにNNのescape()関数の場合はバイトに直したときに危険な文字でなければそのまま1バイト文字として変換します。具体的に"内閣総理大臣 小泉純一郎"なる文字列の変換の相違を示すと:
J2sdk1.4のURLEncoder.encode() |
%93%E0%8A%74%91%8D%97%9D%91%E5%90%62 +%8F%AC%90%F2%8F%83%88%EA%98%59 |
NNのJavaScriptのescape() |
%93%E0%8At%91%8D%97%9D%91%E5%90b %20%8F%AC%90%F2%8F%83%88%EA%98Y |
以上のことからJavaScriptのescape()とunescape()はIEとNN双方に問題があり、Webアプリのようにサーバ/IE/NNともに問題なく情報交換させようとするとこれらの関数は使うべきでない、と結論されます。
バージョン |
代表的なブラウザ |
備考 |
1.0 |
NN2.0 の途中〜 IE3.0 |
JavaScript のオリジナルの仕様 |
1.1 |
NN3 IE3.02+JScript1.3パッチ |
Array objectやイベントなどの追加 |
1.2 |
NN4.0 〜 4.05 IE4 |
Layer/DIV 機能, CSSの追加 |
1.3 |
NN4.06 〜 IE5.0 〜 |
unicodeなど主に ECMA-262対応 |
1.4 |
NN5( 開発中止 ) |
catch/try 等の例外処理など( ECMA-262対応 ) |
1.5 |
Mozilla5( NN6 ) IE6〜 |
ECMA-262 3rd Edition |
2.0 |
? |
ECMA-262 4th Edition |
encodeURI |
||
元の文字列 |
IE6の出力 |
NN7の出力 |
内閣総理大臣 小泉純一郎 |
%E5%86%85%E9%96%A3%E7%B7 %8F%E7%90%86%E5%A4%A7%E8%87%A3 %20%E5%B0%8F%E6%B3%89%E7 %B4%94%E4%B8%80%E9%83%8E |
%E5%86%85%E9%96%A3%E7%B7 %8F%E7%90%86%E5%A4%A7%E8%87%A3 %20%E5%B0%8F%E6%B3%89%E7 %B4%94%E4%B8%80%E9%83%8E |
内閣総理大臣X小泉純一郎 |
%E5%86%85%E9%96%A3%E7%B7 %8F%E7%90%86%E5%A4%A7%E8%87%A3 X%E5%B0%8F%E6%B3%89%E7 %B4%94%E4%B8%80%E9%83%8E |
%E5%86%85%E9%96%A3%E7%B7 %8F%E7%90%86%E5%A4%A7%E8%87%A3 X%E5%B0%8F%E6%B3%89%E7 %B4%94%E4%B8%80%E9%83%8E |
encodeURIComponent |
||
元の文字列 |
IE6の出力 |
NN7の出力 |
内閣総理大臣 小泉純一郎 |
%E5%86%85%E9%96%A3%E7%B7 %8F%E7%90%86%E5%A4%A7%E8%87%A3 %20%E5%B0%8F%E6%B3%89%E7 %B4%94%E4%B8%80%E9%83%8E |
%E5%86%85%E9%96%A3%E7%B7 %8F%E7%90%86%E5%A4%A7%E8%87%A3 %20%E5%B0%8F%E6%B3%89%E7 %B4%94%E4%B8%80%E9%83%8E |
内閣総理大臣X小泉純一郎 |
%E5%86%85%E9%96%A3%E7%B7 %8F%E7%90%86%E5%A4%A7%E8%87%A3 X%E5%B0%8F%E6%B3%89%E7 %B4%94%E4%B8%80%E9%83%8E |
%E5%86%85%E9%96%A3%E7%B7 %8F%E7%90%86%E5%A4%A7%E8%87%A3 X%E5%B0%8F%E6%B3%89%E7 %B4%94%E4%B8%80%E9%83%8E |
カテゴリ |
文字 |
予約文字 |
, / ? : @ & = + $ , |
エスケープしない文字 |
アルファベット, 10進数字, - _ . ! ~ * ' ( ) |
スコア |
# |
したがってdocument.cookieでとりだした文字列をそのまま戻すときはdecodeURI()を使うことになります。クッキーの「値」や「名前」を処理するときはdecodeURIComponent()などを使うとしています。これはJavaScriptがクッキーを(名前、値)のオブジェクトの集合ではなく、単なる文字列として取り扱かったため生じた問題です。これもまたプログラマに混乱を与える要因になります。いずれはそのように改定されることになるでしょう。
ちなみに:
” %E5%86%85%E9%96%A3%E7%B7%8F%E7%90%86%E5%A4%A7%E8%87%A3%20%E5%B0%8F%E6%B3%89%E7%B4%94%E4%B8%80%E9%83%8E”
なる文字列は、decodeURI()もdecodeURIComponent()も同じ” 内閣総理大臣=小泉純一郎”をかえします。
しかしながら、互換性の問題があるのです。つまりj2sdk1.4のURLencoder.encode(String,”UTF-8”)がエスケープする文字セットと、encodeURIのエスケープする文字セットが異なるのです。更に、j2sdk1.4でURLエンコードした文字列がdecodeURI関数では正しく読み取れないことになるのです。
encodeURI関数がエスケープしない文字は下表のようでした。
カテゴリ |
文字 |
予約文字 |
, / ? : @ & = + $ , |
エスケープしない文字 |
アルファベット, 10進数字, - _ . ! ~ * ' ( ) |
スコア |
# |
EncodeURIComponent関数のほうはエスケープしない文字列には予約文字が含まれないのが違うところです。
しかしながら、j2sdk1.4のURLencoder.encode(String,”UTF-8”)がエスケープしない文字は下表のようになっています。赤字且つ斜め文字の部分がエスケープしない文字、但しスペース(SP)は”+”に置き換え且つそれはエスケープしない文字です。
Char Decimal Hex Char Decimal Hex
NUL 0 0
SOH 1 1 STX 2 2
ETX 3 3 EOT 4 4
ENQ 5 5 ACK 6 6
BEL 7 7 BS 8
8
HT 9 9 NL 10 a
VT
11 b NP 12 c
CR
13 d SO 14 e
SI
15 f DLE 16 10
DC1 17 11 DC2 18 12 DC3 19 13 DC4 20 14
NAK 21 15 SYN 22 16
ETB 23 17 CAN 24 18
EM
25
19 SUB 26 1a
ESC 27 1b FS 28 1c
GS
29
1d RS 30 1e
US
31
1f SP 32 20
!
33
21 " 34 22
#
35
23 $ 36 24
%
37
25 & 38 26
'
39
27 ( 40 28
)
41
29 * 42 2a
+
43
2b , 44 2c
- 45 2d . 46 2e
/
47
2f 0 48 30
1
49
31 2 50 32
3
51
33 4 52 34 5 53 35 6 54 36
7
55
37 8 56 38
9
57
39 : 58 3a
;
59
3b < 60 3c
=
61 3d > 62 3e
?
63
3f @ 64 40 A 65 41 B 66 42
C
67
43 D 68 44
E
69
45 F 70 46
G
71
47 H 72 48
I
73
49 J 74 4a
K
75
4b N 78 4e
O
79
4f P 80 50
Q
81
51 R 82 52
S
83
53 T 84 54
U
85
55 V 86 56
W 87 57 X 88 58
Y
89
59 Z 90 5a [ 91 5b \ 92 5c
]
93
5d ^ 94 5e
_ 95 5f ` 96 60
a 97 61 b 98 62
c
99
63 d 100 64
e
101
65 f 102 66
g
103
67 h 104 68
i
105
69 j 106 6a
k
107
6b l 108 6c
m
109
6d n 110 6e
o
111
6f p 112 70 q 113 71 r 114 72
s
115
73 t 116 74
u
117
75 v 118 76
w
119
77 x 120 78
y
121
79 z 122 7a { 123 7b | 124 7c
}
125
7d ~ 126 7e DEL 127 7f |
従って実験サーブレットのプログラムで、
String namestring = "URLエンコードの実験"; String valuestring = "
!\"#$%&'()*+"+'\u002c'+"-./01289:;<=>?@ABCXYZ[\\]"+'\u005e'+'\u005f'+'\u0060'+"abcxyz{|}"+'\u007e'; namestring =
URLEncoder.encode(namestring, urlencoding); valuestring = URLEncoder.encode(valuestring, urlencoding); |
として、’\u0020’から’\u007e’までの文字がどのようにURLエンコードされ、且つJavaScriptのdecodeURI関数がどのようにデコードするかを試してみると次のような結果が得られます。
undecoded
cookie :
URL%E3%82%A8%E3%83%B3%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E5%AE%9F%E9%A8%93 =+%21%22%23%24%25%26%27%28%29*%2B%2C-.%2F01289%3A%3B%3C%3D%3E%3F%40ABCXYZ%5B%5C%5D%5E_%60 abcxyz%7B%7C%7D%7E decoded
cookie : URLエンコードの実験=+!"%23%24%%26'()*%2B%2C-.%2F01289%3A%3B<%3D>%3F%40ABCXYZ[\]^_`abcxyz{|}~ |
つまりdecodeURI関数は予約文字とスコア文字へのデコードはせず、そのままエスケープ表示を返してしまっているのです。実際はencodeURIでエスケープしない文字へのデコード総てが非デコードの対象となります。
「これらの文字を使わない」というのもひとつの解決法かも知れないが、あまり良い手段とはいえません。
また、クッキーを一括エンコードする場合はencodeURIComponent関数を使ってはいけないことも忘れないで下さい。
現状では残念ながらencodeURI、decodeURI、encodeURIComponent、decodeURIComponentといった関数が使えないブラウザが未だ多く利用されている現状であること、これらの関数がJava 2プラットホームのURLエンコードとの互換性がないことを勘案して、cookieとJavaScriptを使ってクライアント/サーバ間で情報交換する場合にはどうしたらよいのでしょうか?結局つぎのような結論となります。
結論
JavaScriptがサーバがセットしたクッキーを処理するようなアプリケーションにおいては:
1) クッキーの名前と値ともにURLエンコードすることが推奨されるが、名前は「危険」でない(URLエンコードに影響されない)文字からなる英数文字列に限定すべきです。telnetなどのツールによる検証やデバッグの便を配慮したものです。
2) NN及びIEのescape()とunescape()関数は問題があるので使ってはなりません。EncodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()も、古いバージョンのブラウザでは対応できていないし、j2sdk1.4との互換性の問題があります。結局J2sdk1.4のjava.netのパッケージにあるURLEncoder.encode()及びURLDecoder.decode()と同じ機能を持ったJavaScriptの関数を用意するのがベストです。そうすれば自分がどのブラウザ上のどのバージョンで走っているかをJavaScriptは識別する必要もなくなります。
URLエンコードはUTF-8に統一する。これはEncodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()がUTF-8を使っているからという理由です。またJavaの仕様においてもUTF-8を推奨しています。日本語では極めて効率が悪いのですが、この世界ではUTF-8を標準的に使ったほうが無難でしょう。
ユニコード(1バイト、2バイト長、4バイト長がある)を外部とバイト列としてやり取りする形式(Unicode Transfer Format: UTF)にはUTF-8とUTF-16が良く使われます。今回はUTF-8によるURLエンコードを検討するので、UTF-8へのURL変換法を紹介します。このまま使えとは申しません。このプログラムを参考にしていただければ幸いです。 |
UCSからUTF-8への変換法は次のテーブルに示したようになります。
UCSからUTF-8への変換法
UCS-2 (UCS-4) |
ビットパターン |
第1バイト |
第2バイト |
第3バイト |
第4バイト |
U+0000 .. U+007F |
00000000-0xxxxxxx |
0xxxxxxx |
|
|
|
U+0080 .. U+07FF |
00000xxx-xxyyyyyy |
110xxxxx |
10yyyyyy |
|
|
U+0800 .. U+FFFF |
xxxxyyyy-yyzzzzzz |
1110xxxx |
10yyyyyy |
10zzzzzz |
|
U+10000.. U+1FFFFF |
00000000-000wwwxx- xxxxyyyy-yyzzzzzzz |
11110www |
10xxxxxx |
10yyyyyy |
10zzzzzz |
この形式の特徴は1バイト文字以外は一番上のビット(MSB)がゼロにならないことで、一番上のビットがゼロの文字は7ビットASCII文字セットそのものだということです。したがって変換のアルゴリズムは極めて簡単です。URL変換に際しては1バイト形式以外の形式では必ず各バイトは%hhとエスケープ形式となります。
java.net.URLencoder.encode(String,”UTF-8”)に相当した関数をJavaScriptで実現する際は、次のようなアルゴリズムになります。
もしその文字が'\u0020’なら、それを'\u002b’に置き換える そうでなければ、 もしその文字が'\u002a’、'\u002d’、'\u002e’、'\u0030’・・'\u0039’、 '\u0042’・・ '\u005a’、'\u005f’、'\u0061’・・'\u007a’でなければ その文字をUTF-8変換し、各バイトを%XXのエスケープ文字列に変換する |
java.net.URLdecoder.decode(String,”UTF-8”)に相当した関数のアルゴリズムは;
もしその文字が'+’なら、それを' ’に置き換える それ以外の文字で、 もしその文字がエスケープ文字列だったらこれをUTF-8変換だとしてユニコード文字に戻す (それ以外の文字はそのまま) |
と簡単なものです。
以下にその関数と、実験用HTMLを示します。これらの関数は将来の拡張4バイト長ユニコード(UCS-4)にも対応しています。このHTMLファイルをブラウザで開くと次のような結果が得られるでしょう。
JavaScriptによるJ2プラットフォーム互換URLエンコード関数とそのテスト original
string : 内閣総理大臣 小泉純一郎
!"#$%&'()*+,-./01289:;<=>?@ABCXYZ[\]^_`abcxyz{|}~ URL
encoded string : %e5%86%85%e9%96%a3%e7%b7%8f%e7%90%86%e5%a4%a7%e8%87%a3+%e5%b0%8f%e6%b3%89%e7%b4%94%e4%b8%80%e9 %83%8e+%21%22%23%24%25%26%27%28%29*%2b%2c-.%2f01289%3a%3b%3c%3d%3e%3f%40ABCXYZ%5b%5c%5d%5e_%60 abcxyz%7b%7c%7d%7e URL
decoded string : 内閣総理大臣 小泉純一郎
!"#$%&'()*+,-./01289:;<=>?@ABCXYZ[\]^_`abcxyz{|}~ |
実際のアプリケーションにおいては:
ア) ウェブ・サーバ側は「値」の文字列をjava.net.URLEncoder.encode(String, “UTF-8”)を使ってURLエンコードしてクッキーの「値」にセットする
イ) ブラウザはWindow.document.cookieで取り出した文字列を
(ア) 「名前」と「値」に危険な文字が含まれていなければそのまま新しいdecodeURL()にかけるか、
(イ) 「値」の文字列をdecodeURL()にかけるか
して正しい文字列に戻すことになります。
ウ) Window.document.cookieを変更する場合は、新しいencodeURL()関数をつかって逆の操作をします。但しWindow.document.cookieに何か新しい「名前」の文字列を代入するということは、今までのクッキーに新しいクッキーが追加される(「名前」が同じならその「値」が書き換えられます。)ことになることに注意しましょう。
参考:
クッキーの中から所定の名前の値を抽出する関数の例です。
function loadCookie(name) {
var allcookies = document.cookie;
if (allcookies == "") return "";
var start = allcookies.indexOf(name + "=");
if (start == -1) return "";
start += name.length + 1; var
end = allcookies.indexOf(';',start);
if (end == -1) end = allcookies.length;
return allcookies.substring(start,end); } |
クッキーの「値」がURLエンコードされている場合は、
var
decodedValue = decodeURL(loadCookie(name));
のようにデコードします。また「名前」や「値」に予約語が含まれていないことがはっきりしている場合は
var allcookies = decodeURL(document.cookie);
という一括処理の使い方も可能です。
<HTML>
<HEAD>
<TITLE>j2 platform equivalent URL
encode/decode functions</TITLE>
<META HTTP-EQUIV="content-type"
CONTENT="text/html; charset=SHIFT_JIS">
</TITLE>
<SCRIPT LANGUAGE="JavaScript">
/* Function
Equivalent to java.net.URLEncoder.encode(String, "UTF-8")
Copyright
(C) 2002, Cresc Corp.
Version:
1.0
*/
function encodeURL(str){
var
s0, i, s, u;
s0
= ""; //
encoded str
for
(i = 0; i < str.length; i++){ //
scan the source
s
= str.charAt(i);
u
= str.charCodeAt(i); //
get unicode of the char
if
(s == " "){s0 += "+";} //
SP should be converted to "+"
else
{
if
( u == 0x2a || u == 0x2d || u == 0x2e || u == 0x5f || ((u >= 0x30)
&& (u <= 0x39)) || ((u >= 0x41) && (u <= 0x5a)) || ((u
>= 0x61) && (u <= 0x7a))){ //
check for escape
s0
= s0 + s; //
don't escape
}
else
{ //
escape
if
((u >= 0x0) && (u <= 0x7f)){ //
single byte format
s
= "0"+u.toString(16);
s0
+= "%"+ s.substr(s.length-2);
}
else
if (u > 0x1fffff){ //
quaternary byte format (extended)
s0
+= "%" + (oxf0 + ((u & 0x1c0000) >> 18)).toString(16);
s0
+= "%" + (0x80 + ((u & 0x3f000) >> 12)).toString(16);
s0
+= "%" + (0x80 + ((u & 0xfc0) >> 6)).toString(16);
s0
+= "%" + (0x80 + (u & 0x3f)).toString(16);
}
else
if (u > 0x7ff){ //
triple byte format
s0
+= "%" + (0xe0 + ((u & 0xf000) >> 12)).toString(16);
s0
+= "%" + (0x80 + ((u & 0xfc0) >> 6)).toString(16);
s0
+= "%" + (0x80 + (u & 0x3f)).toString(16);
}
else
{ //
double byte format
s0
+= "%" + (0xc0 + ((u & 0x7c0) >> 6)).toString(16);
s0
+= "%" + (0x80 + (u & 0x3f)).toString(16);
}
}
}
}
return
s0;
}
/* Function
Equivalent to java.net.URLDecoder.decode(String, "UTF-8")
Copyright
(C) 2002, Cresc Corp.
Version:
1.0
*/
function decodeURL(str){
var
s0, i, j, s, ss, u, n, f;
s0
= ""; //
decoded str
for
(i = 0; i < str.length; i++){ //
scan the source str
s
= str.charAt(i);
if
(s == "+"){s0 += " ";} //
"+" should be changed to SP
else
{
if
(s != "%"){s0 += s;} //
add an unescaped char
else{ //
escape sequence decoding
u
= 0; //
unicode of the character
f
= 1; //
escape flag, zero means end of this sequence
while
(true) {
ss
= ""; //
local str to parse as int
for
(j = 0; j < 2; j++ ) { // get two
maximum hex characters for parse
sss
= str.charAt(++i);
if
(((sss >= "0") && (sss <= "9")) || ((sss
>= "a") && (sss <= "f")) || ((sss >= "A")
&& (sss <= "F"))) {
ss
+= sss; //
if hex, add the hex character
}
else {--i; break;} //
not a hex char., exit the loop
}
n
= parseInt(ss, 16); //
parse the hex str as byte
if
(n <= 0x7f){u = n; f = 1;} //
single byte format
if
((n >= 0xc0) && (n <= 0xdf)){u = n & 0x1f; f = 2;} // double byte format
if
((n >= 0xe0) && (n <= 0xef)){u = n & 0x0f; f = 3;} // triple byte format
if
((n >= 0xf0) && (n <= 0xf7)){u = n & 0x07; f = 4;} // quaternary byte format
(extended)
if
((n >= 0x80) && (n <= 0xbf)){u = (u << 6) + (n & 0x3f);
--f;} //
not a first, shift and add 6 lower bits
if
(f <= 1){break;} //
end of the utf byte sequence
if
(str.charAt(i + 1) == "%"){ i++ ;} //
test for the next shift byte
else
{break;} //
abnormal, format error
}
s0
+= String.fromCharCode(u); //
add the escaped character
}
}
}
return
s0;
}
</SCRIPT>
</HEAD>
<BODY>
<PRE>
JavaScriptによるJ2プラットフォーム互換URLエンコード関数とそのテスト
<SCRIPT LANGUAGE="JavaScript">
s
= "内閣総理大臣 小泉純一郎" + " !\"#$%&'()*+" + '\u002c'+
"-./01289:;<=>?@ABCXYZ[\\]" + '\u005e' + '\u005f' + '\u0060' +
"abcxyz{|}" + '\u007e';
document.writeln("original
string : "+s);
s
= encodeURL(s);
document.writeln("URL
encoded string : "+s);
s
= decodeURL(s);
document.writeln("URL
decoded string : "+s);
</SCRIPT>
</PRE>
</BODY>
</HTML>
最後に皆さんが実際にサーバのプログラムを作成される際の参考として、JSPとJavaScript間でテキストをクッキーを介してやり取りするサンプルをお示しします。 |
このJSPをブラウザがアクセスすると次のような画面が得られるはずです。
動作は次のようです:
1. 最初にユーザはテキストエリアに任意のテキストを入力し、「クッキー書込みと送信」のボタンを押すと、そのテキストはURLエンコードされたのち”userdata”という「名前」の「値」としてクッキーにセットされサーバに送られます。
2. サーバはクライアントから送られてきたクッキーの内容のすべてを先ず「名前」/「値」のセットとしてクライアントへのHTMLテキストに書き込みます。その際「値」のほうはURLデコードしたものを括弧でくくって一緒に書き込みます。
3. サーバは”userdata”という「名前」の「値」の部分をURLデコードしたユーザからのテキストを再度URLエンコードしてクッキーにセットします。
4. クライアントのほうは、サーバからのHTMLテキストを表示すると共に、一緒に送られてきたJavaScriptにより受信したクッキーの内容を生で表示し、次に”userdata”の「値」の部分をURLデコードして表示します。
5. 送信したテキストと送り返されてきたテキストが一致すれば、正しく交信が出来たことになります。
本当にクッキーがサーバとクライアント双方で書き込んでいるか心配ですか?URLエンコードされたクッキーの「値」を見てください。エスケープされた文字がJavaScriptのほうは小文字の16進表示、JSPのほうは大文字の16進表示になっています。これはJavaScriptのNumber.toString(16)メソッドが小文字で出力するのに対し、Java 2プラットホームのURLEncoder.encode(String,”UTF-8”)なるメソッドは大文字で出力するからです。これで双方のURL処理関数が機能し、かつ互換性が取れていることが確認されます。
なお、復帰や改行も入力できますので試してください。HTMLではこれらの文字は表示されませんが、正しくエンコード処理されていることがわかります。ブラウザの設定によっては復帰(CR: %0d)と改行(NL: %0a)双方がクッキーに入る場合もありますし、改行のみの場合もありますので改行処理には注意が必要です。
以下にJSPページを紹介します。JSPのなかにJavaScriptも入っているので読みづらいところは我慢してください。JSPのプログラム部分を赤で、JavaScriptの部分を青で色分けしてあります。このプログラムを実際に体験したのち、読んで頂くと理解が早いと思います。
<%@ page
contentType="text/html; charset=Shift_JIS" session="true"
import="java.net.*" %> <% Cookie[] cookies; Cookie cookie; cookies =
request.getCookies(); cookie = null; if (cookies != null){
for (int i = 0; i < cookies.length; i++){
cookie = cookies[i];
if (cookie.getName().equals("userdata")){break;} }
String encodedUserData = cookie.getValue();
String decodedUserData = URLDecoder.decode(encodedUserData,
"UTF-8");
cookie = new Cookie("userdata",
URLEncoder.encode(decodedUserData, "UTF-8"));
cookie.setMaxAge(300); //
give 5 minute to survive for the cookie
response.addCookie(cookie); } %> <HTML> <HEAD> <TITLE>JavaScript j2
platform equivalent URL encode/decode functions and their test</TITLE> <META
HTTP-EQUIV="content-type" CONTENT="text/html;
charset=SHIFT_JIS"> </TITLE> <SCRIPT
LANGUAGE="JavaScript"> /* Function Equivalent to
URLEncoder.encode(String, "UTF-8") Copyright (C) 2002 Cresc
Corp. Version: 1.0 */ function
encodeURL(str){ var s0, i, s, u; s0 = "";
// encoded str for (i = 0; i <
str.length; i++){ // scan
the source s
= str.charAt(i); u
= str.charCodeAt(i); // get
unicode of the char
if (s == " "){s0 += "+";} // SP
should be converted to "+" else
{
if ( u == 0x2a || u == 0x2d || u == 0x2e || u == 0x5f || ((u >=
0x30) && (u <= 0x39)) || ((u >= 0x41) && (u <=
0x5a)) || ((u >= 0x61) && (u <= 0x7a))){ // check for escape
s0 = s0 + s; //
don't escape }
else {
// escape
if ((u >= 0x0) && (u <= 0x7f)){ // single byte format
s = "0"+u.toString(16);
s0 += "%"+ s.substr(s.length-2);
}
else if (u >
0x1fffff){ //
quaternary byte format (extended)
s0 += "%" + (oxf0 + ((u & 0x1c0000) >>
18)).toString(16);
s0 += "%" + (0x80 + ((u & 0x3f000) >>
12)).toString(16);
s0 += "%" + (0x80 + ((u & 0xfc0) >>
6)).toString(16);
s0 += "%" + (0x80 + (u & 0x3f)).toString(16);
}
else if (u > 0x7ff){ // triple byte format
s0 += "%" + (0xe0 + ((u & 0xf000) >> 12)).toString(16);
s0 += "%" + (0x80 + ((u & 0xfc0) >>
6)).toString(16);
s0 += "%" + (0x80 + (u & 0x3f)).toString(16);
}
else {
// double byte format
s0 +=
"%" + (0xc0 + ((u & 0x7c0) >> 6)).toString(16);
s0 += "%" + (0x80 + (u & 0x3f)).toString(16);
}
} } } return s0; } /* Function Equivalent to
URLDecoder.decode(String, "UTF-8") Copyright (C) 2002 Cresc
Corp. Version: 1.0 */ function
decodeURL(str){ var s0, i, j, s, ss, u,
n, f; s0 = "";
// decoded str for (i = 0; i <
str.length; i++){ // scan
the source str s
= str.charAt(i); if
(s == "+"){s0 += " ";} // "+" should be
changed to SP
else {
if (s != "%"){s0 += s;} // add an unescaped char
else{
// escape sequence decoding
u = 0; // unicode
of the character
f = 1; // escape
flag, zero means end of this sequence
while (true) {
ss = "";
// local str to parse as int
for (j = 0; j < 2; j++ ) {
// get two maximum hex characters to parse
sss = str.charAt(++i);
if (((sss >= "0") && (sss <= "9"))
|| ((sss >= "a") && (sss <= "f")) || ((sss >= "A")
&& (sss <= "F"))) {
ss += sss; // if hex,
add the hex character
} else {--i; break;}
// not a hex char., exit the loop
}
n = parseInt(ss, 16); //
parse the hex str as byte
if (n <= 0x7f){u = n; f = 1;} // single byte format
if ((n >= 0xc0) && (n <= 0xdf)){u = n & 0x1f; f =
2;} // double byte format
if ((n >= 0xe0) && (n <= 0xef)){u = n & 0x0f; f =
3;} // triple byte format
if ((n
>= 0xf0) && (n <= 0xf7)){u = n & 0x07; f = 4;} // quaternary byte format
(extended)
if ((n >= 0x80) && (n <= 0xbf)){u = (u << 6) + (n
& 0x3f); --f;}
// not a first, shift and add 6 lower bits
if (f <= 1){break;}
// end of the utf byte sequence
if (str.charAt(i + 1) == "%"){ i++ ;}
// test for the next shift byte
else {break;}
// abnormal, format error
}
s0 += String.fromCharCode(u); //
add the escaped character
} } } return s0; } /* Function to get cookie parameter
value string with specified name Copyright (C) 2002 Cresc
Corp. Version: 1.0 */ function
loadCookie(name) { var allcookies =
document.cookie; if (allcookies ==
"") return ""; var start =
allcookies.indexOf(name + "="); if (start == -1) return
""; start += name.length + 1; var end =
allcookies.indexOf(';',start); if (end == -1) end =
allcookies.length; return
decodeURL(allcookies.substring(start,end)); } /* Function to send the textarea data
throuth cookie Copyright (C) 2002 Cresc
Corp. Version: 1.0 */ function
sendThis(){ document.cookie="userdata="+encodeURL(document.inForm.text.value); //set data
window.location.reload();
// and reload this page } </SCRIPT> </HEAD> <BODY> JavaScriptによるJ2プラットフォーム互換URLエンコード関数と、JSPによるそのテスト<BR> (URLエンコードされたクッキーのパラメタを介したサーブレットとJavaScript間のデータの交換)<BR><BR> <% if (cookies
!= null){ %> <DIV STYLE="width:
50% word-break:break-all"> サーバーが受け取ったクッキー(URLデコード後):<BR><%
for (int i = 0; i < cookies.length; i++){ %> 名前=<%= cookies[i].getName()
%><BR> 値=<%=
cookies[i].getValue() %><BR> (<%= URLDecoder.decode(cookies[i].getValue(),
"UTF-8") %>)<BR> <% } } %> </DIV> <P STYLE="width:
50%"> クライアントが受け取ったクッキー(URLエンコードされている):<BR> <SCRIPT
LANGUAGE="JavaScript">
document.writeln(document.cookie); </SCRIPT> </P> <P STYLE="width:
50%"> クライアント受信したクッキーの中のデータ部分:<BR> <SCRIPT
LANGUAGE="JavaScript">
document.writeln(loadCookie("userdata")); </SCRIPT> </P> サーバに送信するテキストを書き込んで下さい:<BR> <FORM
NAME="inForm"> <TEXTAREA
ROWS="3" COLS="60" WRAP="soft"
NAME="text"></TEXTAREA><BR> <INPUT
TYPE="button" VALUE="クッキー書込みと送信"
ONCLICK="sendThis()"> </FORM> </BODY> </HTML> |
以上