http://localhost:8080/struts-test/index.do を開くと、
「ログインページ」が表示されたはずだ。

でもこのページは /WEB-INF/pages/login.jsp の内容だ。
でも、ブラウザの URL は /index.do となっている。

で、ものは試しと、以下の URL にアクセスしてみる。
http://localhost:8080/struts-test/WEB-INF/pages/login.jsp
……多分 404 が返ってくるはずである。

何か不思議な感じがしないだろうか?
これに違和感のない人は Servlet をよく理解している。

実は、この挙動は Struts 特有の問題ではなく、
Servlet 自体の仕様に基づいているのだ。

何故このような処理になるかを理解しないまま、
Struts の深い部分に進んでしまうと、
訳が分からなくなってしまう可能性が高い。
そこで、今日はこの仕組みをおさえておこう。

まず、URL にブラウザからアクセスすると、
以下のような処理が行われる。

1. Servlet コンテナが URL へのアクセスを受け取る。
2. 内部で Request と Response オブジェクトを生成する。
3. 対象となる Web アプリケーションを特定する。
4. 要求パスが、/WEB-INF や /META-INF など、
    外部からのアクセスが禁止されているパスの場合は、
    Response に 404 等のエラーを出力して終了。

5. Web アプリケーションの <servlet-mapping> を元に、
    URL を処理する Servlet に転送する。(ディスパッチ)
6. 転送された Servlet が処理を行う。
   Servlet は Response にデータを書き出して終了するか、
   別のパスへの転送を依頼する。(5 番へ)

6 番は、Servlet 固有の処理となっている。

/WEB-INF/pages/login.jsp へのアクセスが弾かれるのは、
/WEB-INF 配下を直接呼び出すことが禁止されているからだ。

では /index.do へのアクセスが何故 JSP で処理されるのか。

http://localhost:8080/struts-test/index.do の場合は、
以下のような流れとなっている。

1. Servlet コンテナが /struts-test/index.do を受け取る。
2. 内部で Request と Response オブジェクトを生成する。
3. Web アプリケーション /struts-test/ を特定する。
4. 要求パス /index.do はアクセスが認められている。
5. /index.do なので、struts に転送される。

6. <Struts ActionServlet の処理>
    Struts の ActionServlet は要求パスから拡張子を取り、
    「/index」のマッピングを設定ファイルから探す。
    /index は /WEB-INF/pages/login.jsp に転送するように
    設定されているので、コンテナを呼び出して、
    /WEB-INF/pages/login.jsp に転送する。

5'. /WEB-INF/pages/login.jsp なので、
    *.jsp にマッピングされた JSP Servlet に転送される。

6'. <JSP Servlet の処理>
    /WEB-INF/pages/login.jsp を処理し、
    Response にデータを書き出して終了する。

実は、このような流れとなっているのである。
ポイントは、「別のパスへの転送」である。

Servlet は連動が可能な仕組みとなっており、
必要であれば他の Servlet を呼び出したり、
異なるパスに転送したりすることができる。

Servlet コンテナが最初に行う転送と少し違うのは、
/WEB-INF 等へのアクセスも可能であるということだ。
(外部からの要求でない限り、確認されない)

もし /index.do から /login.do に転送し、
/login.do から /WEB-INF/login.jsp に転送すれば、
Struts => Struts => JSP と、3 度処理される事になる。

もし /index.do から /login.do に転送し、
/login.do から /index.do に再度転送すれば、
無限ループを作ってしまうことにもなる。

さて、この転送は Servlet 内部でのみ起こっており、
HTTP の転送(リダイレクト)とは直接関係ない。
HTTP のレベルで見れば、1 回の要求 => 応答だけなのである。

Request と Response の寿命は、HTTP 要求の間であり、
Servlet に対する要求の間ではない。
そのため、上記のように Servlet を転々としたとしても、
その属性の値は保存されている。

なので、Struts で前処理をして Request に属性を設定し、
後で JSP でその値を取り出すことなども可能なのである。

この転送機能は非常に強力なのだが、
すこし困った一面もある。

ブラウザから見ると、URL にアクセスし、
サーバからレスポンスが返ってきただけなので、
サーバでどのような処理が行われようと、
当然ながら、ブラウザの URL は要求した時のものだ。

そのため、ブラウザから見ると URL と画面の表示が、
一致しない原因にもなりえるのである。