Hitachi

Cosminexus V11 アプリケーションサーバ 機能解説 基本・開発編(Webコンテナ)


8.2.2 サーブレット実装時の注意事項

サーブレットを実装するときの注意事項を示します。

〈この項の構成〉

(1) 入出力ストリーム利用時の注意

(2) ロケール設定時の注意

ServletResponseクラスのsetLocaleメソッドにLocale.JAPANESEを指定した場合,Content-TypeヘッダのcharsetはShift_JIS(シフトJIS)になります。

(3) URI取得時の注意

HttpServletRequestクラスのgetRequestURIメソッドでは,最適化されたURIが返されます。例えば,「xxx//yyy/zzz」は「xxx/yyy/zzz」に,「xxx/yyy/../zzz」は「xxx/zzz」のように変換されます。

(4) POSTデータの読み込み失敗時の動作について

WebサーバでPOSTデータの読み込みに失敗した場合,Webコンテナで動作するサーブレットでは,ServletRequestクラスの次に示すメソッドの呼び出し時にIllegalStateException例外が発生します。

また,Content-Typeがmultipart/form-dataのフォームデータを受信した場合は,上記のメソッドまたはHttpServletRequestクラスの次に示すメソッドの呼び出し時に,KDJE39336-E のメッセージの出力を伴うIllegalStateException例外が発生することがあります。この場合,受信したフォームデータのサイズが適切かどうかを確認し,適切なサイズのときはwebserver.connector.limit.max_post_form_dataの設定値を見直してください。

(5) 属性の変更に対するイベント通知時の注意

ServletContextAttributeListenerインタフェース,HttpSessionAttributeListenerインタフェース,およびServletRequestAttributeListenerでは,Webコンテナが内部で使用している属性の追加,削除,更新があった場合にもイベントが通知される場合があります。通知されたイベントの属性名を参照して,Webアプリケーションで使用している属性名以外の場合には無視するようにしてください。

(6) ServletContextインタフェース利用時の注意

(7) Webアプリケーションに含まれるディレクトリにアクセスするときの注意

Webアプリケーションに含まれるディレクトリにアクセスするときは,クエリ文字列およびPOSTデータがリダイレクト先リソースで取得できないことがあるため,クエリ文字列およびPOSTデータは付けないようにしてください。

(8) ServletRequestインタフェース利用時の注意

ServletRequestインタフェースのgetRemoteHostメソッドは,リクエストを送信したクライアントのホスト名を返しますが,Webサーバがホスト名を解決できないか,解決しないように設定されている場合はIPアドレスを返します。

既定の設定ではWebサーバの設定がされていないため,IPアドレスを返します。ホスト名を取得する場合は,Webサーバの設定を変更する必要があります。ただし,設定を変更すると,ホスト名の解決のため,レスポンスが遅くなる場合があります。Webサーバの設定の変更方法については,マニュアル「HTTP Server」を参照してください。

(9) プロセス内で複数回実行してはならない処理を実装する場合の注意

1プロセス内で複数回実行してはならない処理をサーブレット中に記述する場合,サーブレットの実行とその処理が同期することがないようにしてください。特に,OTMとの通信を開始するための初期化処理の中には,インスタンスを削除しても終了しない常駐スレッドを生成するものがあります。例えば,TPBrokerの初期化関数であるORB.initメソッドは,呼び出されるたびにGC実行のための監視用常駐スレッドを生成し,このスレッドはプロセス終了まで消えません。そのため,1プロセス内でORB.initメソッドを必要以上に実行すると,不要なGC処理が増え,システム全体の性能が著しく低下するなどの悪影響があります。

このような事態を避けるため,プロセス中で1回だけ実行させたい処理をサーブレットに記述する場合には,その処理がプロセス中で実行済みかどうかをあらかじめ判定する必要があります。具体的には,ある処理が実行済みかどうかの状態を格納する条件フラグとしてstatic変数を任意のクラス中で用意します。static変数の値が「未実行」を意味するものである場合にだけ処理を実行し,値を「実行済み」を意味するものに変更することで,その処理の実行回数をプロセス中で1回だけに限定できます。ただし,次の2点に注意してください。

(10) ServletContextオブジェクトに登録する製品独自の属性

Webコンテナは,Webアプリケーションの制御に必要な情報をjavax.servlet.ServletContextオブジェクトの属性に登録しています。WebアプリケーションでServletContextインタフェースのgetAttributeNamesメソッドによって取得する属性名には,Webコンテナによって登録された属性の名称も含まれます。

Webアプリケーション内でServletContextオブジェクトに属性を登録する時,次の文字列で開始するキー名称を使用しないでください。

また,ServletContextにはJava EEの仕様で定められた属性も追加されるため,これらと同じキー名称の属性を登録しないでください。

(11) ServletRequestクラスのプロキシ取得用メソッドを使用する場合の注意

次に示すjavax.servlet.ServletRequestクラスのメソッドは,リクエストを送信したクライアント,または最後に通ったプロキシの情報を取得するためのメソッドですが,リバースプロキシを使用した環境では,取得する情報がリバースプロキシの情報となります。

(12) javax.servlet.ServletResponseインタフェースのresetメソッド実行時の注意

javax.servlet.ServletResponseインタフェースのgetWriterメソッドを実行したあとに,resetメソッドを実行した場合,HTTPレスポンスのContent-Typeで指定する文字エンコーディングは,次に示すAPIのどれか(すべてjavax.servlet.ServletResponseインタフェース)を使用して,再度同じ文字エンコーディングを指定してください。

注※

Servlet 2.4仕様で追加されたメソッドです。

Servlet 2.4仕様以降では,これらのAPIを使用して文字エンコーディングを設定する場合は,getWriterメソッドを実行する前に呼び出す必要があります。ただし,getWriterメソッドを実行したあとにresetメソッドを実行した場合にかぎり,再度getWriterメソッドを呼び出すまではこれらのAPIで文字エンコーディングを設定できます。

(13) setMaxInactiveIntervalメソッドの引数に0を指定した場合の動作

javax.servlet.http.HttpSessionインタフェースのsetMaxInactiveIntervalメソッドの引数に0を指定した場合,セッションがタイムアウトになることはありません。

(14) java.io.BufferedReaderのmark操作について

javax.servlet.ServletRequestのgetReaderメソッドで得られるjava.io.BufferedReaderは,mark操作をサポートしていません。markSupportedメソッドではfalseが返されます。

(15) setVersionメソッドの引数に1を指定した場合の動作

javax.servlet.http.CookieのsetVersionメソッドの引数に1を指定した場合,Set-Cookieヘッダが付加されます。

(16) getRequestDispatcherメソッドでのパスの指定について

javax.servlet.ServletRequestのgetRequestDispatcherメソッドの引数に「/」ではじまらない相対パスを指定した場合,このサーブレットのサーブレットマッピングに指定したURLパターンからの相対パスになります。URLパターンが「/」で終わっている場合は,親のディレクトリからの相対パスになります。

例えば,サーブレットマッピングを"/a/b/"に指定したサーブレットから,"hello.html"を指定してgetRequestDispatcherメソッドを実行すると,"/a/hello.html"が得られます。

(17) setBufferSizeメソッドを使用してバッファサイズを変更する場合の注意

レスポンス送信時に使用されるサーブレットのバッファは,リクエスト処理スレッドごとに保持されます。javax.servlet.ServletResponseのsetBufferSizeメソッドを実行してバッファサイズを変更した場合,変更したバッファサイズは,同一J2EEサーバ上のほかのWebアプリケーションを含め,該当するスレッドが処理するすべてのリクエストに適用されます。javax.servlet.ServletResponseのsetBufferSizeメソッドを使用してバッファサイズを変更する場合は,(バッファサイズ)×(リクエスト処理スレッド数)分のメモリが確保されることを考慮した上で,メモリ使用量を見積もってください。

なお,一度確保されたバッファは,処理スレッドごとにWebアプリケーションからsetBufferSizeメソッドで更新されるまで有効となります。

(18) HTTPレスポンスのContent-Typeヘッダについての注意

サーブレットでは,javax.servlet.ServletResponseクラスのsetContentTypeメソッドで明示的にContent-Typeを設定していない場合,Content-Typeヘッダを作成しません。そのため,HTTPレスポンスの文字エンコーディングをContent-Typeヘッダの”charset=”フィールドから確認することはできません。

(19) javax.servlet.http.HttpSessionクラスのgetIdメソッドについての注意事項

Servlet 2.4仕様以前に準拠したWebアプリケーションで,無効化されたjavax.servlet.http.HttpSessionオブジェクトのgetIdメソッドを呼び出した場合の動作がServlet仕様とアプリケーションサーバとで異なります。それぞれの動作を次に示します。

Servlet仕様

java.lang.IllegalStateException例外をスローする。

アプリケーションサーバ

nullを返す。

(20) javax.servlet.ServletRequestクラスおよびjavax.servlet.http.HttpServletRequestクラスのメソッドについての注意事項

次の表に示すメソッドで取得した情報をレスポンスに出力する場合は,サニタイズする必要があります。

表8‒12 取得した情報をサニタイズする必要があるメソッド

クラス名

メソッド名

javax.servlet.ServletRequest

getCharacterEncoding()

getContentType()

getInputStream()

getParameter(java.lang.String name)

getParameterMap()

getParameterNames()

getParameterValues(java.lang.String name)

getProtocol()

getReader()

getServerName()

javax.servlet.http.HttpServletRequest

getCookies()

getHeader(java.lang.String name)

getHeaderNames()

getHeaders(java.lang.String name)

getMethod()

getPathInfo()

getPathTranslated()

getQueryString()

getRequestedSessionId()

getRequestURI()

getRequestURL()

getServletPath()

(21) javax.servlet.ServletRequestクラスのgetLocale(getLocales)メソッドについての注意事項

javax.servlet.ServletRequestクラスのgetLocaleメソッド,またはgetLocalesメソッドで取得できるjava.util.Localeオブジェクトは,HTTPリクエストのAccept-Languageヘッダの値から作成します。

Webコンテナでは,Accept-Languageヘッダの値のロケール(ISO言語コード,ISO国コード,またはバリアント)が英字以外を含むかどうかをチェックします。ロケールが英字以外を含む場合は,不正なロケールと判断して,不正なロケールごとにKDJE39546-Wのメッセージをメッセージログに出力して無視します。

不正なロケールを含むAccept-Languageヘッダを受信した場合は,getLocaleメソッド,またはgetLocalesメソッドは正しいロケールのjava.util.Localeオブジェクトだけを返します。Accept-Languageヘッダに指定されたロケールがすべて不正な場合は,Accept-Languageヘッダがないと見なしてサーバのデフォルトロケールを返します。

(22) javax.servlet.http.HttpServletRequestインタフェースのgetServerNameメソッドの戻り値

javax.servlet.http.HttpServletRequestインタフェースのgetServerNameメソッドの戻り値は,リバースプロキシでHostヘッダを書き換えた場合,HTTPクライアントが設定したHostヘッダの値と異なることがあります。

(23) Servlet 2.4以前のinclude先のサーブレットでのレスポンスヘッダの設定

Servlet 2.4以前では,include先のサーブレットでのレスポンスヘッダの設定はすべて無視される仕様です。ただし,アプリケーションサーバでは,Servlet 2.4を使用した場合でも,getSessionでのレスポンスヘッダの設定は有効になります。

(24) MIMEマッピングがない静的コンテンツのコンテンツ形式

MIMEマッピングがない静的コンテンツの場合,Content-Typeは付与されません。

(25) HTTPセッションのアクセス時刻について

セッションIDの付加されたリクエストがWebコンテナに送信されたとき,HTTPセッションのアクセス時刻は現在時刻で更新されます。ただし,すでにセッションがタイムアウトしたり,無効化したりしている場合には該当しません。

HTTPセッションのアクセス時刻は次で使用されます。

(26) Content-Lengthヘッダの値取得時の注意事項

HTTPリクエストにContent-Lengthヘッダが含まれていない場合,javax.servlet.ServletRequestのgetContentLength()メソッドの戻り値,およびjavax.servlet.http.HttpServletRequestのgetIntHeader()メソッドで引数に"Content-Length"を指定した場合の戻り値がServlet仕様とアプリケーションサーバとで異なります。それぞれの戻り値を次に示します。

Servlet仕様

-1を返す。

アプリケーションサーバ

0を返す。