このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。
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 と画面の表示が、
一致しない原因にもなりえるのである。