How are path related values of the request object changed after a forward or include?

winstoneのRequestDispatcherを覗いているときに発見した事実。つーか,正直あまり気にしたこと無かった。


RequestDispatcher.include()/forward()したときのRequest URIの挙動について。includeの方は,Servlet2.3のころ(SRV.8.3.1)から定義されていたようなのだが,forwardは,Servlet2.4(SRV.8.4.2)で定義されたもよう。
#まあ,どっちも知らなかったんで,威張って言うほどのモノではない。:-)


ここにも書いてあった。
Servlet 2.4: What's in store - RequestDispatcher changes


ここからテストした結果を記すよ。
まずはテストページのコード。

== test1.jsp ==
<pre>
  request uri: ${pageContext.request.requestURI}
  context path: ${pageContext.request.contextPath}
  servlet path: ${pageContext.request.servletPath}
  path info: ${pageContext.request.pathInfo}
  query string: ${pageContext.request.queryString}
  foo : ${param["foo"]}
</pre>

<jsp:include page="include.jsp?foo=override" />

FOO : ${param["foo"]}


== include.jsp ==
<hr>
Include:
<pre>
  request uri: ${pageContext.request.requestURI}
  context path: ${pageContext.request.contextPath}
  servlet path: ${pageContext.request.servletPath}
  path info: ${pageContext.request.pathInfo}
  query string: ${pageContext.request.queryString}
  foo : ${param["foo"]}
  -----------
  javax.servlet.include.request_uri: ${requestScope["javax.servlet.include.request_uri"]}
  javax.servlet.include.context_path: ${requestScope["javax.servlet.include.context_path"]}
  javax.servlet.include.servlet_path: ${requestScope["javax.servlet.include.servlet_path"]}
  javax.servlet.include.path_info: ${requestScope["javax.servlet.include.path_info"]}
  javax.servlet.include.query_string: ${requestScope["javax.servlet.include.query_string"]}
</pre>
<hr>

フォワード版はこんなの。

== test2.jsp ==
<jsp:forward page="forward.jsp?foo=override" />


== forward.jsp ==
Forward:
<pre>
  request uri: ${pageContext.request.requestURI}
  context path: ${pageContext.request.contextPath}
  servlet path: ${pageContext.request.servletPath}
  path info: ${pageContext.request.pathInfo}
  query string: ${pageContext.request.queryString}
  foo : ${param["foo"]}
  -----------
  javax.servlet.forward.request_uri: ${requestScope["javax.servlet.forward.request_uri"]}
  javax.servlet.forward.context_path: ${requestScope["javax.servlet.forward.context_path"]}
  javax.servlet.forward.servlet_path: ${requestScope["javax.servlet.forward.servlet_path"]}
  javax.servlet.forward.path_info: ${requestScope["javax.servlet.forward.path_info"]}
  javax.servlet.forward.query_string: ${requestScope["javax.servlet.forward.query_string"]}
</pre>

まず,インクルードについてテストしてみんとす(以下のURLでアクセス)。

test1.jsp?foo=hogehoge

パラメタ:fooの値(hogehoge)が上書きされるかどうかがポイント。結果はこう。

request uri: /WebApplication3/index.jsp
context path: /WebApplication3
servlet path: /index.jsp
path info:
query string: foo=hogehoge
foo : hogehoge

                                                                            • -

Include:
request uri: /WebApplication3/index.jsp
context path: /WebApplication3
servlet path: /index.jsp
path info:
query string: foo=hogehoge
foo : override
-----------
javax.servlet.include.request_uri: /WebApplication3/include.jsp
javax.servlet.include.context_path: /WebApplication3
javax.servlet.include.servlet_path: /include.jsp
javax.servlet.include.path_info:
javax.servlet.include.query_string: foo=override

                                                                            • -

FOO: hogehoge

インクルードされる側のパラメタは上書きされて送られる。んでもって,インクルードされる側のJSP名とかは,リクエストの属性:javax.servlet.include.*で取得できる。


つづいて,フォワードについてテスト。

test2.jsp?foo=hogehoge

インクルードと同じようなURLを投げて,パラメタ:fooの値がどうなるかチェックする。
とりあえず,結果はこう。

Forward:
request uri: /WebApplication3/forward.jsp
context path: /WebApplication3
servlet path: /forward.jsp
path info:
query string: foo=override
foo : override
-----------
javax.servlet.forward.request_uri: /WebApplication3/index_1.jsp
javax.servlet.forward.context_path: /WebApplication3
javax.servlet.forward.servlet_path: /index_1.jsp
javax.servlet.forward.path_info:
javax.servlet.forward.query_string: foo=hogehoge

インクルードと違ってフォワードの場合,フォワード元(test2.jsp)は表示されることはないので,RequestURIとかは,フォワード先(forward.jsp)の値になる。だから,パラメタ:fooも上書きされた値しか取れない(QUERY_STRINGも上書き)。
でも,Servlet2.4からはフォワード元の情報が,リクエストの属性:javax.servlet.forward.*に格納されるようだ。


ついで言うと,ServletContext.getNamedDispatcher(String)の場合は,これらの追加属性(javax.servlet.includeやforward)は付加されないそうな。


「だからどうした?」的な話であるが,知らんかったんでメモ。