S-JIS[2008-09-21/2008-12-31] 変更履歴

HTTPサーブレットリクエスト

サーブレットのservice()(doPost()・getGet())の引数であるHttpServletRequestのメモ。


POSTデータ

HTTPリクエストには、POSTメソッドで送られてきた値が入っている。[2007-07-08]

コンソールにデータを出力する例:

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {

		req.setCharacterEncoding("MS932");
		for (Enumeration i = req.getParameterNames(); i.hasMoreElements();) {
			String key = (String) i.nextElement();
			String val = req.getParameter(key);

			System.out.printf("%s = %s%n", key, val);
		}
	}

HttpServletRequest#setCharacterEncoding()で、リクエストの文字コード体系を指定しておく。(これは、クライアント側で入力に使用した文字コード体系に合わせる)

ファイルアップロード時の取得方法(multipart/form-data)
getParameterValues()


パスの取得

パス(URL・URI)取得関連のメソッド。

メソッド 例(取得されるデータ) 内容 備考
getRequestURL() http://localhost:8080/root/test/zzz/sample.jsp クライアントから要求されたURL。 include等で別のサーブレットが呼ばれた場合でも変わらない。
getRequestURI() /root/test/zzz/sample.jsp クライアントから要求されたURI。
getContextPath() /root クライアントから要求されたURIのコンテキストルート。
getServletPath() /test RequestURIの内、url-patternに一致した部分。 <url-pattern>/test/*</url-pattern>
「*.jsp」等の後方一致だった場合は、RequestURI全て。
getPathInfo() /zzz/sample.jsp RequestURIの内、ServletPathを除いた残りの部分。
無い場合はnull。
 
getQueryString() a=1&b=2 クライアントから要求されたURLの末尾につけられていた値。 http://〜sample.jsp?a=1&b=2
他のgetRequestURL()等にはこの情報は付加されていない。
getAttribute("javax.servlet.include.request_uri") null
/root/WEB-INF/common.jsp
別サーブレットがincludeの際に指定したURI。 1つのリクエストの中で初めて呼ばれた場合はnull。
そうでない場合は、呼び出し元のサーブレットが指定したURIに対する値。
getAttribute("javax.servlet.include.servlet_path") null
/WEB-INF/common.jsp
別サーブレットがincludeの際に指定したURI(のServletPath)。
getAttribute("javax.servlet.include.path_info")   別サーブレットがincludeの際に指定したURI(のPathInfo)。
無い場合はnull。
getAttribute("〜")
javax.servlet.include.request_uri
javax.servlet.include.context_path
javax.servlet.include.servlet_path
javax.servlet.include.path_info
javax.servlet.include.query_string
javax.servlet.forward.request_uri
javax.servlet.forward.context_path
javax.servlet.forward.servlet_path
javax.servlet.forward.path_info
javax.servlet.forward.query_string
     

サーブレット(JSP)では、フォワードインクルードによって他のサーブレットを呼び出す(処理を委譲する)ことが出来る。
その為、大元のクライアントから渡されるURIと、直前のサーブレットによって指定されたURIを別々に取得できるようになっている。

なお、ここで言うインクルードは、サーブレット内から実行されるRequestDispatcher#include()メソッド。
JSPで言えば、標準アクションタグのインクルードタグ<jsp:include page="〜.jsp" />」のこと。
(JSPのincludeディレクティブ<%@include file="〜.jsp" %>」は、別jspファイルの内容を事前コンパイル時に取り込んで自分の一部にしてしまう為、実行時には呼び出されない)


getParameterValues()の順序

getParameterValues(name)は、指定されたパラメーターの値を取得するメソッド。[2008-10-19]
HTML(HTTPのGET/POSTメソッド)の場合、同じ名前のパラメーターを指定することが出来るので、getParameterValues()では、同名のパラメーターの全ての値がString配列として返される。
(ちなみに、getParameter()は、String配列の先頭1個目を返す。が、getParameter()は値が1つしか無い(はず)と分かっている場合に使用する)

<form method="POST">
	<input name="nm" type="text" value="foo">
	<input name="nm" type="text" value="hoge">
	<input name="nm" type="text" value="zzz">
</form>


req.getParameterValues("nm")でString[]{ "foo", "hoge", "zzz" }が返る。


ここで、getParameterValues()が返すString配列内の値の順番は保証されるか?という話題がある。(GoogleでもgetParameterValuesで検索すると、「getParameterValues 順番」が検索候補に出てくる)
getParameterValues()のJavadocには順序に関して特に記述が無い。記述が無いということは、厳密に言えば「保証が無い」ということになるとも言える。
また、HTTPのRFCには、順番に関する規定は特に無いらしい。(参考: @IT会議室のgetParameterValuesについて

しかし、HTML4.01仕様には、<form enctype="application/x-www-form-urlencoded">の場合(つまりデフォルト)は、名前/値はドキュメント(HTML文書)に現れている順序通りとある。

つまり、サーブレットに到達するまで(すなわちブラウザーがセットしたもの)は、HTML内の順番通りに並んでいる(はず)。少なくともHTML4では。
HTMLのバージョン指定方法(DOCTYPE)


そしてサーブレット仕様2.2には、クエリー文字列(GETメソッドによる名前/値)とPOST本体を合わせて同名パラメーターがある場合に“順序がこうなるはず”という例が載っている。
あくまで例なので、厳密に仕様かと問われるとちょっと怪しい気はしないでもないが…。
ちなみにJBoss4.2.3が準拠しているサーブレットのバージョンは2.4(J2EE1.4)だと思うが、サーブレット仕様2.2も2.5も同じ例が載っているので、2.4も同じだろう 。


そいでもって、JBoss(中身はTomcat)の実装も、POSTメソッド(クエリー文字列)の解釈部分は、同名パラメーターが後から来た場合にString配列の末尾に追加するようコーディングされている。 つまり、パラメーターの現れた順番に値が保持される。

結論としては、getParameterValues()の返す値は、HTML内の順番通りに並んでいると思っていいだろう。少なくともJBoss・Tomcatは。


リクエストヘッダー

HTTPのリクエストヘッダーを取得するにはgetHeader()を使用する。

	String referer = req.getHeader("referer");
	for (Enumeration<?> e = req.getHeaderNames(); e.hasMoreElements();) {
		String key = (String) e.nextElement();
		String val = req.getHeader(key);

		String msg = String.format("%s= %s", key, val);
		System.out.println(msg);
	}

ひとつの名前に複数の値が入る可能性がある場合はgetHeaders()(Enumerationを返す)
数値として取得する場合はgetIntHeader()(intを返す)
日付として取得したい場合はgetDateHeader()(longを返す)
を使う。


サーブレットへ戻る / JavaEEへ戻る / Java目次へ戻る
メールの送信先:ひしだま