- PR -

'%'を文字扱いするとき

1
投稿者投稿内容
ume
ベテラン
会議室デビュー日: 2001/09/19
投稿数: 55
投稿日時: 2002-05-16 17:46
お世話になっております。

ある文字列にjava.net.URLEncoderをかけてパラメータにして、
HttpServletRequest.getParameterで受け取るプログラムをつくりました。
ここで、エンコードする文字列に'%'が含まれている場合、
エンコードされたコードは'%25'に変換されるのですが、
これをgetParameterで受け取ったときには'%'になってしまっています。

この現象を防ぐ方法はないでしょうか?
ご教授のほどよろしくお願いします。


[ メッセージ編集済み 編集者: ume 編集日時 2002-05-16 19:25 ]
まりり
ぬし
会議室デビュー日: 2001/12/05
投稿数: 329
投稿日時: 2002-05-16 19:00
何がやりたいのかがちょっと見えないのですが・・・
おっしゃってる現象はまっとうな挙動ですよね?

1. 文字列「%」を送る
2. エンコードされて「%25」となる
3. getParameterで「%25」と受け取りたい

ということでしょうか?
だとしたらgetParameterのあとで「%」→「%25」と変換するだけでは。
ume
ベテラン
会議室デビュー日: 2001/09/19
投稿数: 55
投稿日時: 2002-05-16 19:41
ご回答ありがとうございます。

getParameterで受け取った文字列を次にjava.net.URLDecoderにかけているのですが
ここで'%'しかないとjava.lang.ArrayIndexOutOfBoundsExceptionがおこります。
java.net.URLDecoder('%25')をすると正常に'%'が返ってくるので
'%25'で受け取って使いたいのですが、
getParameterで自動的に変換されているのでしょうか?

しょむ
ぬし
会議室デビュー日: 2001/09/06
投稿数: 430
投稿日時: 2002-05-16 22:33
はあはあ…やっと根拠らしきもの見つけた。

http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2

If the Request-URI is encoded using the "% HEX HEX" encoding [42], the origin server MUST decode the Request-URI in order to properly interpret the request.

ちうわけで、サーブレットコンテナは decode ずみのものを web app に渡すべき、なんでしょうかね。

# しかし、どんな参考書でも GET の場合は URLDecoder 使えなんて
# 書いてない気がするんですけど…
# POST と GET でわたってくる形式が違ってたらめんどくさいっすよ。
Paul
ベテラン
会議室デビュー日: 2002/04/30
投稿数: 75
お住まい・勤務地: 東京
投稿日時: 2002-05-17 20:23
>ちうわけで、サーブレットコンテナは decode ずみのものを web app に渡すべき、なんでしょうかね。
># しかし、どんな参考書でも GET の場合は URLDecoder 使えなんて
># 書いてない気がするんですけど…
そうですね。Servlet-APIでは、getParameterは必ずURLDecodeした値を返します。
そのため、GETリクエストで送信するURLに漢字などの非ASCII文字列が含まれる
場合は、あらかじめURLEncodeを行っておく必要があるのです。

たとえば、name=ABC と data=漢字 というクエリを送ろうとするなら、
http://hostname/context/page?name=ABD&data=%8a%bf%8e%9a
というようにしておきます。
そうすればサーバ側では getParameterで "ABC"、"漢字" が取れます。
(ただし、環境によっては
String data1 = new String( data.getBytes("8859_1"), "SJIS");
のような、ワークアラウンドが必要にはなりますが・・・ )
いずれにしましても、POSTと同じインタフェースになるわけです。

URLデコードして復元された値に、さらにURLDecoderをかけたら、冗長処理に
なってしまい、元の文字列を壊してしまいます。

K.Nakagome
ume
ベテラン
会議室デビュー日: 2001/09/19
投稿数: 55
投稿日時: 2002-05-22 13:37
ご回答ありがとうございます。

>たとえば、name=ABC と data=漢字 というクエリを送ろうとするなら、
>http://hostname/context/page?name=ABD&data=%8a%bf%8e%9a
>というようにしておきます。
>そうすればサーバ側では getParameterで "ABC"、"漢字" が取れます。

まさにNakagomeさんのご説明の処理をしようとしています。
getParameterでString型に値を受け取っているのですが
日本語が文字化けして受け取られてしまい、URLdecoderにかけると
正常に受け取ってくれます。
なのでURLdecoderが必要だと考えていたのですが
getParameterで日本語が正しく取れないことの方に問題があったのですね。

doPostで画面の入力値を受け取るときにもgetParameterを使っているのですが
こちらは正しく受け取っています。
どのあたりに問題があるのでしょうか?
たびたびすみませんがアドバイスお願いします。
Paul
ベテラン
会議室デビュー日: 2002/04/30
投稿数: 75
お住まい・勤務地: 東京
投稿日時: 2002-05-22 18:18
> doPostで画面の入力値を受け取るときにもgetParameterを使っているのですが
> こちらは正しく受け取っています。
> どのあたりに問題があるのでしょうか?
コンテンツエンコードとプラットフォームのディフォルトエンコーディングの相違の
問題ではないかと思います。

実例をあげて説明します。
プラットフォームがWin32であれば以下のコードが正しく動作するはずです。

----------------<< from.jsp >>--------------------------------------------
<%@ page contentType="text/html; charset=Shift_JIS" import="java.net.URLEncoder" %>
<html><head><title>TEST Page</title></head>
<body>
<a href="to.jsp?name=ABD&data=%8a%bf%8e%9a">受け取るページへ(リテラル)</a><br/>
<a href="to.jsp?name=ABD&data=<%= URLEncoder.encode( "漢字" ) %>">受け取るページへ(URLEncoder)</a>
</body>
</html>
------------------------------------------------------------------------

-----------------<< to.jsp >>---------------------------------------------
<%@ page contentType="text/html; charset=Shift_JIS" %>
<html><head><title>TEST Page</title></head>
<body>
<a href="from.jsp">戻る</a><br/>
<%
java.util.Enumeration e = request.getParameterNames();

while(e.hasMoreElements()) {
String key = (String)e.nextElement();
String[] values = request.getParameterValues(name);

for(int i=0; i < values.length; ++i) {
String value = new String( values[i].getBytes("ISO8859_1"), "Shift_JIS") ;
if(i == 0) {
%>
<%= key %> = <%= value %>
<% }
else {
%>
,<%= value %>
<% }
}
%>
<br/>
<% } %>
</body>
</html>
------------------------------------------------------------------------

上の例では、from.jspのリテラルのURLとURLEncoderで処理されたURLが同じに
ならなければ、to.jsp側で正しい結果を得ることはできません。
"漢字"をShift_JIS文字エンコーディングでURLエンコーディングされれば
%8a%bf%8e%9a になりますが、それ以外の文字エンコーディングでは異なります。

ポイントは、URLEncoderのencode()では、文字エンコーディングを指定できない点に
あります。encode()の機能は「文字列を x-www-form-url 符号化形式に変換します。」という
説明がありますが、文字列の文字エンコーディング体系については記述がありません。
したがって、プラットフォームのディフォルト文字エンコーディングで実装されているようです。

●回避策について
上の原因によるものであれば、回避策としては以下のようなものが考えられます(択一)。

1、J2SDKのURLEncoderを利用する場合、コンテンツのエンコーディングをプラットフォームの
ディフォルト文字エンコーディングにあわせる。

2、文字エンコーディングを指定できる自前のURLEncoderを実装し、それを利用してコンテンツと
同一の文字エンコーディングを指定してURLエンコードする。

3、GETとPOSTの処理ロジックを分けて、getParameter()後の文字エンコーディング変換
コード中でプラットフォームのディフォルト文字エンコーディングを指定する。

私はあるプロジェクトで、上の 2の方法を採用しました。
実はそのようなユーテリティを作って、オープンソースで公開している人がプロジェクト内に
いまして(Mr.westbay)、彼のパッケージを利用したという経緯でした。
http://sourceforge.net/projects/juli/
jp.co.beacon_it.utils.StringUtil.classのなかのencodeEscape()メソッドです。

K.Nakagome

[ メッセージ編集済み 編集者: nakagome 編集日時 2002-05-23 10:54 ]
1

スキルアップ/キャリアアップ(JOB@IT)