05_HttpServletRequest

11647 ワード

一、リクエスト転送(forward)とリソース含む(include)
 
一、リクエスト転送(forward)とリソース含む(include)
1、要求転送(forward)
forwardメソッドはリクエストをRequestDispatcherオブジェクトパッケージのリソースに転送するために使用され、サーブレットプログラムはこのメソッドを呼び出して転送する前にリクエストに対していくつかの事前処理を行うことができる.後述するMVCアーキテクチャでは、forwardメソッドがコアメソッドであり、コントローラコンポーネント(Controller)は、このメソッドを使用してビューコンポーネント(Viewer)にジャンプし、ビューコンポーネントに応答内容を生成してブラウザに表示させる.forwardメソッドを使用する場合は、次の問題に注意してください.
(1)forwarメソッドを呼び出す前にサーブレットプログラムに書き込まれたコンテンツの一部がクライアントに実際に転送された場合、forwardメソッドはIllegalStateException異常を投げ出す.IllegalStateExceptionはRuntimeExceptionのサブクラスであり、システムレベルの異常であるため、プログラムコードではtryを強制的に使用する必要はない...catch文で処理します.
(2)RequestDispatcherを呼び出す.forwardメソッドの場合、サーブレットコンテナは、ターゲットリソースパスに基づいて、現在のHttpサーブレットRequestオブジェクトの要求パスとパラメータ情報を調整します.
(3)forwardメソッドが呼び出される前にサーブレットエンジンのバッファにコンテンツが書き込まれた場合、バッファに書き込まれたコンテンツがクライアントに実際に出力されていない限り、forwardメソッドは正常に実行され、出力バッファに書き込まれたコンテンツはクリアされる.forwardメソッドが呼び出された後、呼び出し元プログラムがサーブレットエンジンバッファに書き込み操作を実行し続ける場合、これらの書き込み操作の実行結果は無視されます.
説明:forwardの前にバッファの内容がクライアントに出力された場合、最初の例外が報告されます.クライアントに実際に出力されていない場合はクリアされ、forward後に呼び出し元がバッファに情報を書き続ける場合も無視される.これはforwardメソッドが要求を転送したためであり、今回の要求は完全に呼び出し元が応答し、呼び出し元が行ったバッファへの書き込みはすべて無効な情報と考えられる.
(4)呼び出し元プログラムで設定された応答状態コードと応答ヘッダは無視されず、呼び出し元プログラムで設定された応答状態コードと応答ヘッダも無視されない.注意:RequestDispatcherの場合.includeメソッド呼び出しは、呼び出し元プログラムが設定した応答ステータスコードと応答ヘッダのみが有効であり、呼び出し元プログラムで設定した応答ステータスコードと応答ヘッダは無視されます.
説明:forwardメソッドの呼び出し者と被呼び出し者は対等であり、同じRequestとResponseを共有していると考えられるため、サーブレット自体によるResponseヘッダ情報の修正規則化に合致する限り、どこで設定された応答ヘッダと応答コードが有効であるかにかかわらず、RequestとResponseを修正する権利がある.例えば、呼び出し者にresponseを設定.setContentType("text/html;charset=ISO8859-1");その後、呼び出し元にresponseを設定.setContentType("text/html;charset=GB2312"); この2つの設定がresponseである場合.getWriter()の前に最終応答ヘッダ符号化は、最終的に設定されたGB 2312に従って処理される.呼び出し者でも呼び出し者でもresponse.getWriter()の後にcontentTypeを設定する情報は、同じサーブレットでもresponse.getWriter()の後に行っても無効です.
(5)呼び出し元と呼び出し元のアクセスURLが同一ディレクトリに属さない場合、呼び出し元が出力したコンテンツに相対URLを用いたアクセス経路が含まれている場合、元の呼び出し元に対するURLは呼び出し元に対するURLとなる.これは、ブラウザが現在アクセスしているのが呼び出し元プログラムのURLであることしか知らないため、応答内容における相対経路を呼び出し元プログラムのURLを基準として計算することにより、呼び出し元プログラムが出力する相対経路が呼び出し元に対する経路ではなくなってしまうためである.
説明:呼び出し元で相対パスを使用すると、サーブレットエンジンは、/TestWSServer/Forwardedサーブレットのような相対パスをブラウザに返し、ブラウザが相対パスを絶対パスに変換する責任を負います.ブラウザにとって、現在の要求パスが呼び出し元であることしか知りません.したがって、呼び出し元を基準パスとして変換されます.これにより、呼び出し元で相対パスを使用する場合、ラベル文を使用してWebページの相対パスの基準アドレスを指定するか、呼び出し元で基準パスとして相対パスを使用するかの2つの解決策があります.
上記のいくつかの注意事項を総合すると、呼び出し者と被呼び出し者の3つの異なる点と1つの同じ点にまとめることができます.
異なる点
バッファアクション
バッファのデータが本当にクライアントに出力されると、forwardメソッドを呼び出すと異常が報告されます.本当にクライアントに出力されていない場合、呼び出し元のバッファに対するすべての操作は無視され、呼び出し元の出力バッファの内容だけに注目します.
異なる点
forward時のRequestのパスとパラメータ
forwardの場合、サーブレットコンテナは、現在のHttpサーブレットRequestオブジェクトの要求パスとパラメータ情報をターゲットリソースパスに基づいて調整します.
異なる点
相対パスの問題
被呼び出し者で相対パスを使用すると、応答は相対パスをそのままブラウザに返し、ブラウザはこの相対パスグループに基づいて絶対パスをつづり、ブラウザは今回要求された呼び出し者情報のみを知ることができるので、呼び出し者のパスをベースとして絶対パスをつづり、これにより,呼び出し者と被呼び出し者のパスが同じディレクトリにないと問題が発生する.上記のように、ラベルまたは呼び出し元のパスを基準パスとして相対パスを使用することしかできません.
同じ点
レスポンスヘッダとレスポンスコードの設定
呼び出し者と呼び出し者が設定した応答コードと応答ヘッダは無視されません.ただし、responseを設定するなど、本来のサービスの規定に従う必要があります.setContentType("text/html;charset=XXX"); の場合、呼び出し元と被呼び出し者が設定した応答ヘッダは無視されないが、最終的には1回目の呼び出しresponseに有効に設定.getWriter()の前の最後は、同じサーキットでもresponseが初めて呼び出されるためである.getWriter()の前の最後の設定が最終設定になります.
上記のforwardジャンプの例については、次のようになります.
public class ForwardingServlet extends HttpServlet {

	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//           
		response.setDateHeader("Expires", 0);
		response.setHeader("Cache-Control", "no-cache");
		response.setHeader("Pragma", "no-cache");
		
		//            
		response.setContentType("text/html;charset=ISO8859-1");
		response.setContentType("text/html;charset=GB2312");		
		PrintWriter out = response.getWriter();		
		response.setContentType("text/html;charset=UTF-8");
		
		//    forward Request     URI,      URL  
		System.out.println("URI = " + request.getRequestURI());
		System.out.println("QueryString = " + request.getQueryString());
		System.out.println("URL = " + request.getRequestURL().toString());
				
		String china = "  ";
		//forward           
		out.println("   :forward       ");
		request.getRequestDispatcher("/ForwardedServlet?p1=" + URLEncoder.encode(china, "GBK")).forward(request, response);
		//forward                
		out.println("   :forward       ");
	}
}

 
public class ForwardedServlet extends HttpServlet {

	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		//      Request    URI,      URL  ,                  
		PrintWriter out = response.getWriter();
		out.println("<a href='ForwardedServlet' >    <a/><br>");
		out.println("URI:" + request.getRequestURI() + "<br>");
		out.println("QueryString:" + request.getQueryString() + "<br>");
		out.println("URL:" + request.getRequestURL().toString() + "<br>");
		
		String p1 = request.getParameter("p1");
		String chP1 = null;
		if(p1 != null) {
			chP1 = new String(p1.getBytes("ISO8859-1"),"GB2312");
		}
		
		//  forward        
		out.println("parameter p1:" + chP1 + "<br>");		
	}

}
	<servlet>
		<servlet-name>ForwardingServlet</servlet-name>
		<servlet-class>com.test.servlet.ForwardingServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>ForwardingServlet</servlet-name>
		<url-pattern>/Servlet/ForwardingServlet</url-pattern>
	</servlet-mapping> 	
	<servlet>
		<servlet-name>ForwardedServlet</servlet-name>
		<servlet-class>com.test.servlet.ForwardedServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>ForwardedServlet</servlet-name>
		<url-pattern>/ForwardedServlet</url-pattern>
	</servlet-mapping> 	

バックグラウンド出力:
URI =/TestWSServer/Servlet/ForwardingServletQueryString = p1=param1URL = http://localhost:8080/TestWSServer/Servlet/ForwardingServlet
 
ページの出力内容は次のとおりです.
自分を訪問する URI:/TestWSServer/ForwardedServletQueryString:p1=%D6%D0%B9%FAURL:http://localhost:8080/TestWSServer/ForwardedServletparameterp 1:中国
 
従来のバックグラウンドの出力内容から見ると、forwardプロセスのいくつかの注意点を現象に基づいて説明することができます.
注意事項
げんしょう
forward転送時にRequestのパスとパラメータ情報を変更します
バックグラウンド出力のURI、クエリーパラメータとURLパスが異なる
呼び出し元がバッファに書き込まれたコンテンツがクライアントに実際に書き込まれない前にforwardはクリアされ、forward後に呼び出し元がバッファにコンテンツを書き続けると無視されます(もちろんflushでクライアントに強制的に書き込まれた後、forwardの場合はここでシミュレーションしません)
クライアント出力なし:呼び出し元:forwardの前に書き込まれたコンテンツと呼び出し元:forwardの後に書き込まれたコンテンツ
呼び出し者と被呼び出し者の応答ヘッダと応答コードの修正は無視されないがresponseのように.setContentType("text/html;charset=XXXX"); このような応答ヘッダ情報は、responseが初めて呼び出される.getWriter();前の最後の設定が有効です
responseを呼び出す.getWriter();その後、responseが呼び出されても.setContentType("text/html;charset=UTF-8");応答情報は呼び出しresponseに従う.getWriter();前回最後に設定されたGB 2312は、応答内容を出力する
被呼び出し者が相対パスを使用する場合、自分を基準にすることはできません.呼び出し者を基準にすべきです.ブラウザは相対パスを絶対パスに変換する際に呼び出し者のパス情報しか知らないので、呼び出し者を基準にして絶対パスを生成します.もちろんタグでもこの問題は解決できます
自分のリンクへのアクセスをクリックすると、ブラウザのアドレスはhttp://localhost:8080/TestWSServer/Servlet/ForwardedServletで、私たちが望んでいるhttp://localhost:8080/TestWSServer/ForwardedServletではありません.
 
2、資源含む(include)
     RequestDispatcher.includeメソッドは、RequestDispatcherオブジェクトがカプセル化されたリソースコンテンツを現在の応答コンテンツの一部として含み、プログラム可能なサーバ側の組み込み機能を実現するために使用される.含まれるサーブレットプログラムは、応答メッセージのステータスコードと応答ヘッダを変更することはできません.このような文が存在する場合、これらの文の実行結果は無視されます.RequestDispatcherを呼び出します.includeメソッドの場合、サーブレットコンテナはHttpサーブレットRequestオブジェクトの情報を調整しません.HttpサーブレットRequestオブジェクトは、その初期のURLパスとパラメータ情報を保持します.つまり、現在のアクセスパスを呼び出し元プログラムで検索すると、呼び出し元プログラムのURLパスではなく、呼び出し元プログラムのURLパスが得られます.
デモコードは次のとおりです.
public class IncludingServlet extends HttpServlet {

	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		response.setDateHeader("Expires", 0);
		response.setHeader("Cache-Control", "no-cache");
		response.setHeader("Pragma", "no-cache");
		
		response.setContentType("text/html;charset=GB2312");
		PrintWriter out = response.getWriter();
		String china = "  ";		
		RequestDispatcher rd = getServletContext().getRequestDispatcher("/IncludedServlet?p1=" + URLEncoder.encode(china));	
		out.println("before including " + "<br>");
		rd.include(request, response);
		out.println("after including " + "<br>");
	}	
}

 
public class IncludedServlet extends HttpServlet {

	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=ISO8859-1");
		PrintWriter out = response.getWriter();	
		out.println("  " + "<br>");
		out.println("URI =" + request.getRequestURI() + "<br>");
		out.println("QueryString = " + request.getQueryString()	+ "<br>");
		out.println("URL = " + request.getRequestURL().toString() + "<br>");
		out.println("parameter p1 = " + new String(request.getParameter("p1").getBytes("ISO8859-1"),"GB2312") + "<br>");
	}
	
}

 
	<servlet>
		<servlet-name>IncludingServlet</servlet-name>
		<servlet-class>com.servlet.IncludingServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>IncludingServlet</servlet-name>
		<url-pattern>/IncludingServlet</url-pattern>
	</servlet-mapping> 
			<servlet>
		<servlet-name>IncludedServlet</servlet-name>
		<servlet-class>com.servlet.IncludedServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>IncludedServlet</servlet-name>
		<url-pattern>/IncludedServlet</url-pattern>
	</servlet-mapping> 

出力結果:
中国
URI =/TestWSServer/IncludingServlet
QueryString = null
URL = http://localhost:8080/TestWSServer/IncludingServlet
parameter p 1=中国