Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2022/11/24 Java仕様勉強会: Jakarta Servlet

Satoshi Seto
November 24, 2022

2022/11/24 Java仕様勉強会: Jakarta Servlet

2022/11/24 Java仕様勉強会で話したJakarta Servletの基礎の説明です。
Jakarta Servletは普段はフレームワークの奥底に隠れていますが、理解をしているとウェブサーバーが何をしているのかについて深く知ることができます。
JSFやSpring等多くのフレームワークがServletをもとに構築されているので、Servletを知ることで効率的にそれらのフレームワークを使いこなすことができるようになるでしょう。
このセッションではある程度Javaでウェブ開発をしたことがある人向けにServlet APIの解説をしつつ、Jakarta EE 10に変わってからの注意点について解説します。

資料内で参考として挙げているURLは以下です。(クリックしても開かなかったので為念)
https://jakarta.ee/specifications/servlet/6.0/
https://www.eclipse.org/community/eclipse_newsletter/2020/february/3.php
https://jamesgdriscoll.wordpress.com/2010/02/09/servlet-history/
https://megascus.hatenablog.com/entry/20180418/1524034199

Satoshi Seto

November 24, 2022
Tweet

More Decks by Satoshi Seto

Other Decks in Technology

Transcript

  1. Jakarta Servlet
    レッドハット株式会社
    2022.11.24
    瀬戸
    1
    11月24日Java仕様勉強会

    View Slide

  2. 2
    ▸ 名前:瀬戸 智
    ▸ Twitter: @megascus
    ▸ Servletを使い始めたのは2005年から。
    ▸ ServletとかJPAあたりが好きで、一時期個人でServletとJPAのJavaDocを翻訳していた。
    ・ そのあとPleiadesの人が機械翻訳をしてくれるようになったので現時点では意味なし。
    自己紹介

    View Slide

  3. 3
    ▸ はじめに
    ▸ HTTP
    ▸ Servlet
    ▸ Servletの高度な機能
    ▸ Servlet 非互換・新機能
    アジェンダ

    View Slide

  4. はじめに(1/5)
    4

    View Slide

  5. 5
    ▸ Jakarta ServletはJavaのウェブサーバーの礎となる仕様
    ▸ Javaで書かれたライブラリの多くがServletに依存しており知っていると拡張しやすくなる
    (かもしれない)
    ・ Spring、Jakarta EE、Velocity、FreeMarker、Thymeleaf・・・
    Jakarta Servlet を学ぶメリット

    View Slide

  6. 6
    ▸ 今はEclipse FoundationsのJakarta EEワーキンググループで公開されています。
    https://jakarta.ee/specifications/servlet/6.0/
    ▸ 最新版は6.0
    Servletの仕様

    View Slide

  7. 7
    ▸ 1996年5月に最初の発表、12月にServlet仕様の初版リリース
    ・ Java本体のリリース日は1996年1月
    ・ 現時点で25年以上の歴史
    ▸ 詳細は以下
    https://www.eclipse.org/community/eclipse_newsletter/2020/february/3.php
    https://jamesgdriscoll.wordpress.com/2010/02/09/servlet-history/
    この資料書いてる人は2005年ごろからServletを使い始めたので伝聞でしか知らないよ!
    Servletの始まり

    View Slide

  8. 8
    ▸ 当時(1990年代)はCGIが全盛。
    ・ CGI=Commmon Gateway Interface
    ・ ウェブサーバーが外部クライアントからのリクエストを受けてプログラム(プロセス)を起動
    し、その結果をクライアントに返す仕組み。
    ▸ CGIは移植性に問題があり、各OSでプログラムを実装しなおす必要があった。
    ・ C言語とかでOSごとに実装しなおす。
    ▸ 当時の貧弱なPCだとプログラム(プロセス)の起動のオーバーヘッドが大きかった。
    ・ プログラムを常駐させて繰り返しリクエストを処理することでプロセス起動の負荷を下げ
    て、より多くの処理を行えるのではないだろうか?
    Servletの始まり

    View Slide

  9. 9
    ▸ 低負荷のHTTPサーバーを実装する。
    ・ Javaアプリを常駐させることで負荷を軽減する。
    ▸ どこでも動くようにする。
    ・ いわゆる Write once, run anywhere.
    ▸ 複数のリクエストを軽量に同時に処理できる。(=マルチスレッド)
    =Javaでやりたいこと。
    Servletのやりたいこと

    View Slide

  10. 10
    ▸ 現在ではハードウェアのスペックが上がったため、常駐型ではなく、必要に応じてリソー
    スを確保する方式(いわゆるサーバーレス)が増えてきている。
    ▸ しかしながら、高負荷だとサーバーレスの起動時間が気になるケースも出てくることが広
    く知られており、その場合は暖機運転等、サーバーレスでも常駐処理が検討される。
    (参考)サーバーレス

    View Slide

  11. HTTP(2/5)
    11

    View Slide

  12. 12
    ▸ ServletはHTTPサーバーをJavaで実現するための仕様。
    ▸ 仕様を読むとHTTPの仕様の記載されたRFC(※)
    へのリンクが多数出てくる。
    ・ RFC=Request For Comments
    ▸ Servletが何かを理解するためにはHTTPの理解が必須。
    ※RFCとは、インターネット技術の標準化などを行うIETF(Internet Engineering Task
    Force)が発行している、技術仕様などについての文書群。TCP/IP関連のプロトコル(通信規
    約)の標準仕様などが記されたもので、インターネット上で公開されており誰でも入手・閲覧
    することができる。 IT用語辞典e-Wordsより https://e-words.jp/w/RFC.html
    ServletはHTTPの薄いラッパー

    View Slide

  13. 13
    • RFC 1630 Uniform Resource Identifiers (URI)
    • RFC 1738 Uniform Resource Locators (URL)
    • RFC 3986 Uniform Resource Identifiers (URI): Generic Syntax
    • RFC 1945 Hypertext Transfer Protocol (HTTP/1.0)
    • RFC 2045 MIME Part One: Format of Internet Message Bodies
    • RFC 2046 MIME Part Two: Media Types
    • RFC 2047 MIME Part Three: Message Header Extensions for non-ASCII
    text
    • RFC 2048 MIME Part Four: Registration Procedures
    • RFC 2049 MIME Part Five: Conformance Criteria and Examples
    • RFC 6265 HTTP State Management Mechanism
    • RFC 7258 Pervasive Monitoring Is an Attack
    • RFC 7540 Hypertext Transfer Protocol Version 2 (HTTP/2)
    • RFC 7541 HPACK: Header Compression for HTTP/2 (HPACK)
    Servlet仕様から参照されているRFC
    • RFC 7230 Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and
    Routing
    • RFC 7231 Hypertext Transfer Protocol (HTTP/1.1): Semantics and
    Content
    • RFC 7232 Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests
    • RFC 7233 Hypertext Transfer Protocol (HTTP/1.1): Range Requests
    • RFC 7234 Hypertext Transfer Protocol (HTTP/1.1): Caching
    • RFC 7235 Hypertext Transfer Protocol (HTTP/1.1): Authentication
    • RFC 7301 Transport Layer Security (TLS) Application-Layer Protocol
    Negotiation Extension (ALPN)
    • RFC 7168 The Hyper Text Coffee Pot Control Protocol for Tea Ef
    (HTCPCP-TEA)
    • RFC 2617 HTTP Authentication: Basic and Digest Authentication
    • RFC 2119 Key words for use in RFCs to Indicate Requirement Levels

    View Slide

  14. 14
    ▸ HTTP=HyperText Transfer Protocolの略称。
    ▸ 名前の通りテキストをやり取りするための仕様。
    ▸ リソースはhttp://から始まるURL(もしくはURI)であらわされる。
    ・ URLの例 http://www.example.com/context/file?param1=value1&param2=value2
    ▸ クライアントはURLを使用してサーバーにアクセスし、レスポンスを受け取る。
    HTTPとは

    View Slide

  15. 15
    HTTPとは
    1対1でリクエストに対してサーバーが処理をしてレスポンスを返す。これだけ。※例外アリ
    クライアント ②サーバーが
    処理をする
    ①リクエスト(Request、要求)
    を投げる
    ③レスポンス(Response、応答)
    を受け取る

    View Slide

  16. 16
    POST /xxxx/yyyyy HTTP/1.1
    Host: www.example.com
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
    (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
    Accept-Language: ja,en-US;q=0.9,en;q=0.8
    param1=value1&param2=value2
    HTTPリクエストの例
    ヘッダー
    空行
    メッセージボディ
    リクエストライン

    View Slide

  17. 17
    例) POST /xxxx/yyyyy HTTP/1.1
    ▸ メソッド名 ←この次に説明
    ▸ アクセスする先のリソースのパス
    ▸ HTTPのバージョン
    ・ だいたい HTTP/1.1 か HTTP/1.0 (あまり気にしなくてもよいので省略)
    HTTPリクエスト-リクエストライン

    View Slide

  18. 18
    ▸ GET、HEAD、POST、OPTIONS、PUT、DELETE、TRACE、PATCH、LINK、UNLINKが
    ある。
    ▸ サーバー上のリソースに対してどういう操作を行うか。
    ▸ GETならこういう操作をしてほしいというのは定義されているが、実際にサーバー側で何
    を行うのかは実装次第。実装されていない場合もある。主な仕様は以下の通り。
    ・ GET - サーバー上のリソースの内容を返す。
    ・ HEAD - GETと同じだが、レスポンスヘッダーのみを返す。
    ・ POST - サーバー上にフォームデータを送り処理をする。
    HTTPリクエスト-リクエストライン-メソッド

    View Slide

  19. 19
    例) Host: www.example.com
    ▸ KEY-VALUE形式のメタデータ。
    ・ KEY + “: ” + VALUE の形式
    ▸ リクエストの付帯情報を表す。
    ▸ 大文字、小文字は区別されない。
    ▸ 決められたものがいくつかあるが、任意のものを追加可能。
    HTTPリクエスト-ヘッダー

    View Slide

  20. 20
    ▸ Accept-Language: ja,en-US;q=0.9,en;q=0.8
    ・ クライアント側で受け入れたい言語
    ▸ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like
    Gecko) Chrome/107.0.0.0 Safari/537.36
    ・ クライアント側で使ってるブラウザの情報
    ▸ If-Modified-Since: Mon, 18 Jul 2016 02:36:04 GMT
    ・ クライアント側でこのデータをキャッシュしてるからこれ以降変更がなければ更新デ
    ータを送ってこなくてよいよという情報
    HTTPリクエスト-ヘッダー-主なヘッダー

    View Slide

  21. 21
    例) param1=value1&param2=value2
    ▸ メッセージ本体、ペイロード本体、エンティティ本体とも呼ばれる。(本体=Body)
    ▸ GET、HEADメソッドの場合は使用できない。(サーバー側では無視されるべき。)
    ・ GET、HEADでパラメーターを使用したい場合はURLにくっつける。
    ▸ この例はリクエストパラメーター(=フォームで入力されたデータ)が送られている場合。
    ・ これ以外にはbase64でエンコードされたバイナリデータが送られる場合が多い。
    HTTPリクエスト-メッセージボディ

    View Slide

  22. 22
    ▸ Base64はバイナリデータをテキストに直す方式。
    ・ だいたい元のデータから33%~35%ぐらい増える。
    ▸ HTTPはテキストのやり取りの取り決めなので、バイナリデータを渡す場合は文字列への
    変換が必要になる。
    ・ もともとはメールでよく使われている方式だったがHTTPでも採用された。
    ・ MIME(Multipurpose Internet Mail Extensions)の一種。
    ※HTTPはバイナリデータをやり取りするのには向かない方式なので、ファイルのやり取りを
    するのが主目的の場合は別の方式を検討したほうが良いです。
    base64でエンコードされたメッセージボディ

    View Slide

  23. 23
    ▸ 30Mのファイルサイズまでしかアップロードできないようにしようと考えてリクエストサ
    イズを30Mで制限したら、実際には20M強までしかアップロードできなくなってしまった。
    ▸ base64エンコードされるとサイズが増えるのとヘッダーの分があるため41Mぐらいで制限
    するのが正しい。(30M * 1.35+α)
    (補足)base64が起因となるよくある事故

    View Slide

  24. 24
    ▸ メッセージボディの後ろにつけられるkey-value形式のフィールド
    ・ ヘッダーに transfer-Encoding: chunkedが付いている場合のみ使用できる。
    ▸ ファイルアップロード時にCRCを計算して付けておくとか、利用方法が思いつくけど、実
    際に使用されている例は見たことがない。
    ・ 使用例知ってたら教えてください。
    ▸ HTTPレスポンスのメッセージボディの後にも付けられる。
    (補足)HTTPリクエスト-トレーラーフィールド

    View Slide

  25. 25
    HTTP/1.1 200 OK
    Date: Wed, 16 Nov 2022 09:23:34 GMT
    Expires: -1
    Cache-Control: private, max-age=0
    Content-Type: text/html; charset=Shift_JIS
    X-Frame-Options: SAMEORIGIN
    Transfer-Encoding: chunked
    HTTPレスポンスの例
    ヘッダー
    空行
    メッセージボディ
    ステータスライン

    View Slide

  26. 26
    例) HTTP/1.1 200 OK
    ▸ HTTPのバージョン
    ・ だいたい HTTP/1.1 か HTTP/1.0 (あまり気にしなくてもよいので省略)
    ▸ ステータスコード ←この後説明
    ▸ ステータスの理由
    ・ サーバー側が自由に設定できるステータスコードの詳細な理由
    HTTPレスポンス-ステータスライン

    View Slide

  27. 27
    ▸ レスポンスの状態コードを表す3桁の整数コード。 例)418
    ▸ クライアントからのリクエストをサーバーがどのように解釈して結果としてどういう処理
    が行われたのかを返す。一番上の数字で大まかな理由がわかる。
    ・ 100番台 リクエストは受け取られ、処理は継続されている。
    ・ 200番台 リクエストは受け取られて、理解されて、処理された。
    ・ 300番台 リクエストを処理するために、ほかのリソースへのアクセスを必要とする。
    ・ 400番台 クライアント側のリクエストにエラーがあり処理できなかった。
    ・ 500番台 サーバー側で処理に失敗した。
    HTTPレスポンス-ステータスライン-ステータスコード

    View Slide

  28. 28
    ▸ 200 OK リクエストに成功され正常に処理された。
    ▸ 301 Moved Permanently リソースが恒久的に他のURLに移動した
    ▸ 307 Temporary Redirect 一時的なリダイレクト
    ▸ 401 Unauthorized 認証が必要なページに認証なしでアクセスした
    ▸ 403 Forbidden リソースへのアクセスが禁止されている
    ▸ 404 Not Found リソースが見つからなかった
    ▸ 408 Request Timeout サーバーでの処理に時間がかかりすぎてタイムアウトした
    ▸ 500 Internal Server Error サーバー内部のプログラムでエラーが発生した
    よくあるステータスコード

    View Slide

  29. 29
    301 Moved Permanently リソースが恒久的に他のURLに移動した
    307 Temporary Redirect 一時的なリダイレクト
    ▸ 307を返すべきところで、301を返してしまい、2度とアクセスできなくなることがある。
    ▸ 一般的にHTTPクライアント(ブラウザ)は301が返されたリソースは301が返されたことを記
    憶し、キャッシュが有効な限りは2度とアクセスしに行かない。
    (補足)301と307の使い分けに注意!

    View Slide

  30. 30
    例) Host: www.example.com
    ▸ KEY-VALUE形式のメタデータ。
    ・ KEY + “: ” + VALUE の形式
    ▸ レスポンスの付帯情報を表す。
    ▸ 大文字、小文字は区別されない。
    ▸ 決められたものがいくつかあるが、任意のものを追加可能。
    HTTPレスポンス-ヘッダー

    View Slide

  31. 31
    ▸ Content-Type: text/html; charset=Shift_JIS
    ・ ファイルのコンテンツタイプ
    ▸ Date: Wed, 16 Nov 2022 09:23:34 GMT
    ・ リソースの更新日時
    ▸ Cache-Control: private, max-age=0
    ・ コンテンツをキャッシュしてよいかどうか
    HTTPレスポンス-ヘッダー-主なヘッダー

    View Slide

  32. 32
    例) ▸ サーバーにアクセスして取得した実コンテンツ。
    ▸ 複数ファイルを返すことも可能。(今回は説明しません)
    ▸ バイナリデータの場合はbase64でエンコードされる。(のでレスポンスサイズが増える)
    HTTPレスポンス-コンテンツ

    View Slide

  33. 33
    各種ブラウザの開発者ツールを使うことで確認ができます。
    (例) Chromeの場合はブラウザ上でF12
    (補足)実際のHTTP通信を見たい場合

    View Slide

  34. 34
    Proxy型のツールでhttp通信をフックして通信内容を変更できるツールがいくつかあります。
    私はBurpSuiteをよく使います。(Community Editionなら無償)
    https://portswigger.net/burp
    (補足)実際のHTTP通信を色々変更してみたい場合

    View Slide

  35. 35
    ▸ サーバーとやり取りする情報をクライアント側に保存する仕組み。
    ・ 一度保存された情報は次のリクエスト時にサーバーに送られる。
    ▸ サーバーで生成したユニークキーをクライアントに送り付けてCookieとして保存させるこ
    とで複数のクライアントを区別することが可能に。(=セッション)
    Cookie(クッキー)

    View Slide

  36. 36
    ▸ サーバーからSet-Cookieヘッダを送ることでクライアント側に保存される。
    例) Set-Cookie: key=value; expires=Tue, 14-Feb-2023 12:05:23 GMT; path=/;
    domain=.example.com
    ▸ key=valueの後にいくつかのオプション(属性)を付けることが可能。
    ・ expiresはCookieの有効期間(保管期限)
    ・ DomainはそのCookieを送り返してほしいドメイン
    ・ Pathはサーバーの中でそのCookieを送り返してほしいパス
    Cookieの生成

    View Slide

  37. 37
    ▸ 一度保存されたCookieは期限切れになるまではリクエストヘッダーに入れられてサーバー
    に送られ続ける。
    例)Cookie: key=value
    Cookieの送信

    View Slide

  38. 38
    ▸ Cookieはクライアント側のユーザーが自由に変更できる。
    ▸ 重要なデータはCookieに保存しないようにしてください。
    ・ ブラウザゲームでゲーム内通貨の情報をCookieに保存していたためチートが可能にな
    っていたとか・・・・
    (注意!)Cookieに変更されて困る情報は保存しない

    View Slide

  39. 39
    ▸ HTTPの仕組みには存在しない。
    ▸ Cookieを使って同じユーザーからのリクエストを特定し、ユーザーの情報をサーバー側で
    保持する。
    ・ Cookieを使わない方式もあるけどほぼ使われないので省略。
    例) Set-Cookie: jsessionid=8315ba76-6604-11ed-bb8d-00155daa0717
    Session(セッション)

    View Slide

  40. 40
    ▸ 自分でも簡単に実装はできるが、実装しないでください。
    ▸ アプリケーションサーバーの多くではデフォルトで機能としてついている、もしくはオプ
    ションで機能があります。
    ▸ 自分で実装する場合セキュリティ上のリスクとなる可能性があります。
    ・ セッションを特定するための文字列が単純で第三者が推測できることによるセッショ
    ン乗っ取り事件 → セッションハイジャック
    Sessionの注意

    View Slide

  41. 41
    ▸ サーバー側から複数のURLのコンテンツ(リソース)をクライアントに送る仕組み
    ▸ Googleが提案してServletでも実装されているが、つい最近Chromeから処理が除去されて
    動かなくなりました。Servletでも非推奨になるでしょう?
    ・ CDN(コンテンツデリバリーネットワーク)の使用が一般的になり、サーバー側で複数
    のリソースをキャッシュ目的で返すよりもCDN経由の方が負荷軽減になりやすいとい
    うことが分かったため。
    (参考)その他のHTTP : HTTP/2 Server Push

    View Slide

  42. 42
    ▸ Googleが提案している新しいHTTPの仕様。
    ▸ TCPの代わりにUDPを使う。
    ▸ Servlet仕様では扱われていません。
    (参考)その他のHTTP : HTTP/3 QUIC

    View Slide

  43. 43
    ▸ HTTPS = HyperText Transfer Protocol Secure
    ▸ httpは平文でやり取りをするがhttpsは暗号化してやり取りを行う。
    ▸ 最近はhttp通信は極力なくし、すべてをhttpsにしたほうが良いと言われている。
    (参考)その他のHTTP : HTTPS

    View Slide

  44. 44
    ▸ HTTPはテキストでやり取りをする。
    ・ バイナリデータのやり取りには非効率。
    ▸ Cookieでサーバーの情報をクライアント側に保存できる。
    ・ ユーザーは自由に変更することができる。
    ▸ SessionはHTTPの仕組みではない。
    ・ セキュリティ上の問題となるので自分では実装しないこと。
    ここまでのまとめ

    View Slide

  45. Servlet (3/5)
    45

    View Slide

  46. 46
    ▸ Javaのウェブサーバーの礎となる、Webアプリケーションを作るための仕様。
    ▸ 仕様で決められてるのはだいたい以下の通り。
    ・ 複数のアプリケーションをどうやって動作をさせるか
    ・ アプリケーションの構造(ディレクトリ構成、設定ファイル)
    ・ アプリケーションの作り方(=API仕様)
    Jakarta Servlet とは

    View Slide

  47. 47
    ▸ Servletを動かすためのコンテナ
    ・ いわゆるアプリケーションサーバーに組み込まれているWebアプリケーションを動か
    す仕組み
    ・ 単独のアプリケーション内で動作させる場合もある
    ・ =組み込みサーブレットコンテナ
    ・ Spring-Boot(組み込みTomcat)とか
    Servletコンテナ

    View Slide

  48. 48
    ▸ 複数のユーザー作成のアプリケーションを動作させることができる(場合もある)
    ▸ 複数のアプリケーションを安定して動作できるように相互のアプリケーションは分離され
    ている。
    ▸ コンテナが安定して動作できるようにアプリケーションからコンテナは操作ができないよ
    うになっている。
    ・ コンテナ側からユーザー作成のクラスを参照する事は制限されている。
    ・ アプリケーションに含まれるクラスでコンテナ側のクラスを上書きできると、
    ユーザーアプリケーションがコンテナの動作を自由に変更できることになるので困る。
    Servletコンテナの特徴

    View Slide

  49. 49
    ▸ ユーザーが作成する処理の塊の単位。コンテキストとも呼ばれる。
    ▸ アプリケーションは特定の構造をもったディレクトリ、もしくはそれをzipで固めて拡張子
    をwar(Web ARchive)としたもの、のどちらかになる。
    ・ アプリケーションサーバーによってはどちらかしか受け付けない場合もある。
    (ユーザーの)アプリケーション

    View Slide

  50. 50
    AppRoot
    │ file1 ← 外部からアクセスされる可能性のあるファイル
    │ file2 ・・・
    ├─META-INF
    └─resources
    └─WEB-INF
    │ web.xml (ファイル)
    ├─classes
    └─lib
    アプリケーションのディレクトリ構造

    View Slide

  51. 51
    ▸ /META-INF/ アプリケーションのメタ情報が含められる。
    ▸ /META-INF/resources/ 少し前に流行ったWebJarsが含められる。
    ▸ /WEB-INF/ アプリケーションの設定ファイル、実行ファイルが含められる。
    ▸ /WEB-INF/classes/ アプリケーションの実行に必要なclassファイルが含められる。
    ▸ /WEB-INF/lib/ アプリケーションの実行に必要なライブラリ:jarが含められる。
    これらのディレクトリの内部は外部から直接参照する事ができない。
    ※WebJarsはjsやcss等のファイルを圧縮してjarに固めたもの。
    アプリケーションのディレクトリ構造

    View Slide

  52. 52
    ▸ プログラム経由で見られるべきViewのテンプレートファイルがWEB-INFもしくはMETA-
    INFの外側に置かれていて、直接実行できてしまう。
    ▸ 当然権限制御等はされていないので、見られてはいけないものが外部に公開されている。
    ▸ ロジックが実行されてから表示されることが前提とされているものの、ロジックが実行さ
    れていないので、サーバーエラーとしてログに記録され緊急対応が必要になる。
    ・ 直接参照されたくないファイルはすべてWEB-INFの下に置くか、別の方法でアクセス
    制御を行いましょう。
    (補足)よくある事故

    View Slide

  53. 53
    複数のアプリケーションがサーバーにデプロイされている場合は、デフォルトではURLのホス
    トの一階層下のパスでどのアプリケーションがリクエストを処理するべきかが判断される。
    一般的にコンテキストパスと呼ばれる。
    コンテキストパスが空(=ルートコンテキスト)の場合もある。
    http://www.example.com/context/path/to/servlet
    複数のアプリケーション

    View Slide

  54. 54
    ▸ Servletコンテナの設定ファイル
    ▸ 以前はこのファイルが必須だったが、現時点では必須ではない。
    ▸ この後いくつかの設定の説明をアノテーションを使って行うが、同等の事をすべて
    web.xmlに記載することができる。
    ▸ Servlet仕様ではデフォルトでリクエスト、レスポンスがISO 8859-1(ラテン文字のみ)で扱
    われるので、UTF-8にする設定を入れる必要があるかもしれない。
    UTF-8
    UTF-8
    /WEB-INF/web.xml

    View Slide

  55. 55
    ▸ 動いているサーブレットコンテナで使われているServletのバージョンと、web.xmlのヘッ
    ダーのバージョンが一致してる必要がある。
    ・ 一致していない場合は一部機能が使えない場合がある。
    ▸ 古いアプリケーションを最新のアプリケーションサーバーに移植している場合は更新漏れ
    に注意!
    (注意)web.xmlのヘッダーについて

    View Slide

  56. 56
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
    https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
    version="6.0"
    metadata-complete="false">
    (参考) Tomcatのバージョンごとのweb.xmlのヘッダー
    https://megascus.hatenablog.com/entry/20180418/1524034199
    (参考)Jakarta Servlet 6.0バージョンのヘッダー

    View Slide

  57. 57
    ▸ HttpServlet
    ・ サーバー側での処理を実装するクラス
    ・ 実際の処理をこれのサブクラスとして実装する。
    ▸ HttpServletRequest
    ・ クライアントからのリクエストを表すクラス
    ▸ HttpServletResponse
    ・ クライアントへのレスポンスを表すクラス
    Servlet APIでコアとなる3クラス

    View Slide

  58. 58
    HttpServletの関連クラス
    HttpServlet
    GenericServlet
    <>
    Servlet

    View Slide

  59. 59
    HttpServletの関連クラス
    HttpServlet
    GenericServlet
    <>
    Servlet
    HTTPプロトコルに依存しない汎用のサーブレット
    HTTPプロトコル用のサーブレット
    コンテナからみた汎用の
    サーブレットインターフェース

    View Slide

  60. 60
    ▸ もともとはServletがHTTP以外のプロトコルにも対応する予定があったため作られた。
    ・ Ex) FTP、SFTP等、もしくは未知のプロトコル。
    ▸ ただし、現時点ではHTTP以外は対応していないため、あまり意味がない。
    ▸ 通常はHttpServletのみを使用すればよい。
    (補足)GenericServlet

    View Slide

  61. 61
    ▸ HTTP用のリクエスト、レスポンスを表すインターフェース。
    ・ サーブレットコンテナによって実体が生成される。
    ▸ 汎用プロトコル用のServletRequest 、ServletResponse も存在する。
    ・ GenericServletと同じ理由であまり気にしなくてよい。
    HttpServletRequest、HttpServletResponse

    View Slide

  62. 62
    HttpServletに存在して、最初に意識しなければいけないメソッドは以下の通り
    ▸ ServletコンテナによってServletが起動するときに呼び出されるinit()
    ▸ ServletコンテナによってServletが終了するときに呼び出されるdestroy()
    ▸ HTTPリクエストを受け付けたときに起動されるservice()
    ▸ service()からHTTPメソッドによって分岐するdoGet()、doPost()、doHead()、doPut()、
    doTrace()、doOptions()、doDelete()
    これらを必要に応じてオーバーライドしたサブクラスを作成する。
    HttpServletのメソッド

    View Slide

  63. 63
    CGIが実行毎にプロセスを起動してオーバーヘッドが大きかったのをServletは常駐することで
    オーバーヘッドを減らす。
    ▸ 最初にコンテナが起動したとき、もしくは最初にアクセスがあった場合にServletの初期化
    処理が行われる。(init()メソッド)
    ▸ クライアントからリクエストが送られてくるたびに処理を行う。(service()メソッド)
    ▸ 最後にコンテナが終了するときにServletの破棄処理を行う。(destroy()メソッド)
    (思い出すシリーズ)Servletの実現したい事

    View Slide

  64. 64
    (思い出すシリーズ)HTTPとは
    1対1でリクエストに対してサーバーが処理をしてレスポンスを返す。これだけ。※例外アリ
    クライアント ②サーバーが
    処理をする
    ①リクエスト(Request、要求)
    を投げる
    ③レスポンス(Response、応答)
    を受け取る

    View Slide

  65. 65
    HTTPとは(Servletの場合)
    1対1でリクエストに対してサーバーが処理をしてレスポンスを返す。これだけ。※例外アリ
    クライアント ②Servlet
    ①HttpServletRequest
    ③HttpServletResponse

    View Slide

  66. 66
    Servletの実装例
    ▸ @WebServletアノテーションを付けてHttpServletをextendsして実装する。

    View Slide

  67. 67
    ▸ @WebServletアノテーションを付けてHttpServletをextendsしたクラスを用意する。
    ▸ service()、doGet()、doPost()、doHead()、doPut()、doTrace()、doOptions()、
    doDelete()のいずれかを実装する。
    ▸ HttpServletRequestからクライアントの情報を読み取り、HttpServletResponseに返したい
    情報を書き込む。
    Servletの書き方

    View Slide

  68. 68
    Servletをコンテナに登録するために使用する。web.xmlに同等の事を記載することができる。
    ▸ name – Servletの名前を付ける。(管理用)
    ▸ urlPatterns (必須) – どのURLでServletが起動するか。実際はアプリケーションのコンテキ
    ストパスの後ろの部分に紐づく。*で任意のURLを指定できる。
    http://www.example.com/context/path/to/servlet
    ▸ loadOnStartup – Servletの実行順序、正の整数を指定するとServletコンテナの起動時に数
    字の小さい順に起動する。(指定しない場合はいつ起動するかは不定。通常は初回アクセス
    時。)
    @WebServletの概要(とよく使う属性)

    View Slide

  69. 69
    POST /xxxx/yyyyy HTTP/1.1
    Host: www.example.com
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
    (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36
    Accept-Language: ja,en-US;q=0.9,en;q=0.8
    param1=value1&param2=value2
    (思い出すシリーズ)HTTPリクエストの例
    ヘッダー
    空行
    メッセージボディ
    リクエストライン

    View Slide

  70. 70
    クライアントからのリクエストを表したもの。以下のようなメソッドがある。
    ▸ #getMedhod() - リクエストのメソッドを取得する。
    ▸ #getRequestURL() – リクエストのURLを取得する。
    ▸ #getHeader(String) –キーを指定してヘッダーの値を取得する。
    ▸ #getPrameter(String) –キーを指定してリクエストパラメーターの値を取得する。
    リクエストパラメーターはURLの一部(?の後の&で連結されたkey=value、もしくはメッセ
    ージボディに入ってくる&で連結されたkey=value)
    HttpServletRequest

    View Slide

  71. 71
    ファイルアップロードは大量のデータを扱う必要が出てくるため、扱いが特殊になっている。
    ▸ Servletに@MultipartConfigアノテーションを付ける。
    ・ ファイルアップロードできる最大サイズ等を指定。
    ▸ HttpServletRequest#getParts()で取得できる。
    (補足)ファイルアップロード

    View Slide

  72. 72
    HTTP/1.1 200 OK
    Date: Wed, 16 Nov 2022 09:23:34 GMT
    Expires: -1
    Cache-Control: private, max-age=0
    Content-Type: text/html; charset=Shift_JIS
    X-Frame-Options: SAMEORIGIN
    Transfer-Encoding: chunked
    (思い出すシリーズ)HTTPレスポンスの例
    ヘッダー
    空行
    メッセージボディ
    ステータスライン

    View Slide

  73. 73
    クライアントへのレスポンスを表したもの。以下のようなメソッドがある。
    ▸ #setStatus(int) – レスポンスのステータスコードを指定する。
    ▸ #setHeader(String, String) - ヘッダーの値を指定する。#setContentType()等、よく知ら
    れたヘッダーに対応するメソッドも存在する。
    ▸ #getWriter() / #getOutputStream() - レスポンスボディに書き込むためのWriter /
    OutputStreamを取得する。テキストかバイナリデータかで使い分ける必要がある。どちら
    かしか取得できず、両方を呼び出すと例外が発生する。
    HttpServletResponse

    View Slide

  74. 74
    ▸ クライアントへ返すレスポンスのバッファーサイズが決められており、ボディ
    (Writer/OutputStream)に一定以上書き込んでからヘッダーに書き込もうとするとエラーに
    なる。
    ・ バッファーサイズは実装依存で変更可能な場合が多い。
    ▸ 何がヘッダーに書き込まれるのか意識して実装を!
    ▸ サーバーサイドでの処理を完全に終了させてからHttpServletResponseへの書き込みを開始
    するのが無難。(=ModelとViewの分離)
    (補足)HttpServletResponseへの書き込み

    View Slide

  75. 75
    クライアント側で保存してほしいデータを送信する、取得する。
    HTTP CookieをJavaで取り扱うためのCookieクラスが存在する。
    ▸ HttpServletRequest#getCookies() – クライアント側から送られてきたCookieを取得する。
    ▸ HttpServletResponse#addCookie(Cookie) – クライアント側にCookieを送信する。
    ・ Cookieを削除したい場合はCookie#setMaxAge (0)を呼び出したものを送信する。
    Cookieの取り扱い

    View Slide

  76. Servletの高度な機能
    (4/5)
    76

    View Slide

  77. 77
    複数のServletを組み合わせる
    複数のServletに処理を分散して書くことができると便利な場面が存在する。
    例外処理(表示)を一か所で行う、画面に表示する共通のヘッダーを一か所で生成する等。
    クライアント ②Servlet
    ①HttpServletRequest
    ③HttpServletResponse

    View Slide

  78. 78
    ▸ web.xmlにerror-pageタグを追加する。
    例)
    404
    /path/to/servlet

    ※locationにはservlet以外に静的ファイル等も指定可能。
    ▸ 処理を呼び出す側では HttpServletResponse#sendError(int)を呼び出す。
    ※引数はHTTPステータスコード。
    特定のステータスコード時の処理を共通化する

    View Slide

  79. 79
    ▸ HttpServletRequest#getRequestDispatcher(String)を呼び出して取得した
    RequestDispatcherを使用する。
    ※引数は他のServletへのPATH
    ▸ RequestDispacherではさらに以下のメソッドを呼び出して他のServletの処理を実行する。
    ・ #include() – 呼び出し元のクライアントへの出力をそのままにする。
    ・ #forward() – 呼び出し元のクライアントへの出力をクリアする。
    ※呼び出し元のServletでレスポンスに大量のデータを書き込んでいて、バッファがあふれて
    クライアントにレスポンスが返っていた場合にはエラーになる。
    汎用的に他のServletを呼び出す

    View Slide

  80. 80
    複数のServlet間でデータの受け渡しができるように値のスコープが定義されている。
    ▸ リクエストスコープ(HttpServletRequest) – ユーザーからのリクエストが送られてきてレ
    スポンスが返し終わるまで有効なスコープ
    ▸ セッションスコープ(HttpSession) - 同じユーザーからのリクエストを処理するときに複数
    のリクエストの間で共有できるスコープ
    ▸ アプリケーション(コンテキスト)スコープ(ServletContext) – アプリケーション内全体で共
    有できるスコープ
    複数のServletでのデータの受け渡し(スコープ)

    View Slide

  81. 81
    ユーザーからのリクエストを受け取りレスポンスを返し終わるまで有効なスコープ
    key-value形式で属性値(オブジェクト)を保持する。
    ▸ HttpServletRequest#getAttribute(String)で値を取得。
    ▸ HttpServletRequest#setAttribute(String, Object)で値を設定。
    keyとしてjakarta.から始まるものは設定してはいけない。コンテナによって予約されている。
    リクエストスコープ

    View Slide

  82. 82
    ▸ Servletをまたいで処理をするときにひとつ前のServletが何か等、いくつかの値をリクエス
    トスコープの属性として取得することができる。
    ・ ひとつ前に実行されたServletの名前等
    ・ 一覧についてはRequestDispatcherの定数フィールドを参照。
    ▸ RequestDispatcherに書かれている以外にも情報を取得できるものがあるが省略。
    (補足)コンテナによって設定される値

    View Slide

  83. 83
    ユーザーの情報をサーバー側で保持をする。
    HttpSessionインターフェースで抽象化され、実装クラスは以下のメソッドで取得できる。
    ▸ HttpServletRequest#getSession(boolean)
    ▸ HttpServletRequest#getSession()
    引数にfalseを指定すると、セッションがない場合はnullが返ってくる。引数無しを使うかtrue
    を指定するとセッションがない場合は新しくセッションが作成される。
    セッションスコープ

    View Slide

  84. 84
    key-value形式で属性値(オブジェクト)を保持する。
    ▸ HttpSession#getAttribute(String)で値を取得。
    ▸ HttpSession#setAttribute(String, Object)で値を設定。
    複数サーバーでセッションのレプリカを行うときはvalueはSerializableである必要がある。
    また、複数スレッドで同時に扱われる場合があるので値の操作は同期をとって行う必要がある。
    keyとしてjakarta.から始まるものは設定してはいけない。コンテナによって予約されている。
    セッションスコープ

    View Slide

  85. 85
    アプリケーション内で共有したい情報を設定する。
    一般的には初期起動時のみに書き込んで、それ以降は読み取り専用として扱うのが良い。
    ▸ HttpServlet#getServletContext()で取得するServletContextクラスで扱われる。
    ※ServletContextにはスコープとしての情報以外にアプリケーション(コンテキスト)の情報へ
    アクセス、設定を行うメソッドが存在する。
    アプリケーション(コンテキスト)スコープ

    View Slide

  86. 86
    key-value形式で属性値(オブジェクト)を保持する。
    ▸ ServletContext#getAttribute(String)で値を取得。
    ▸ ServletContext #setAttribute(String, Object)で値を設定。
    複数スレッドで同時に扱われる場合があるので値の操作は同期をとって行う必要がある。
    keyとしてjakarta.から始まるものは設定してはいけない。コンテナによって予約されている。
    アプリケーション(コンテキスト)スコープ

    View Slide

  87. 87
    ▸ それぞれのスコープへの書き込み、読み込み、削除を感知できるリスナー。
    ▸ インターフェースを実装したうえで@WebListenerアノテーションを付ける。
    ▸ 詳細はJavaDocを参照のこと。
    ・ jakarta.servlet.ServletRequestAttributeListener – リクエストの属性用
    ・ jakarta.servlet.http.HttpSessionAttributeListener – セッションの属性用
    ・ jakarta.servlet.ServletContextAttributeListener – アプリケーション(コンテキスト)の
    属性用
    スコープのAttribute(属性)のリスナー

    View Slide

  88. 88
    ▸ 属性のリスナーのほかに以下のリスナーが存在する。
    ▸ インターフェースを実装したうえで@WebListenerアノテーションを付ける。
    ▸ 詳細はJavaDocを参照のこと。
    ・ jakarta.servlet.ServletContextListener – アプリケーションの起動、終了
    ・ jakarta.servlet.ServletRequestListener – リクエストの受付、返送
    ・ jakarta.servlet.http.HttpSessionIdListener – セッションの有効化、無効化
    ・ ログイン時ではないので注意!
    (補足)そのほかのリスナー

    View Slide

  89. 89
    (参考)リクエストのリダイレクト
    サーバーサイドでステータスコード302を投げることで、クライアントに別のURLへのリクエスト
    のし直しを指示することができる。この場合、サーバーサイドでは複数のリクエストとして処理さ
    れるので、リクエストスコープでは値を引き継げない。
    クライアント ②Servlet
    リクエスト
    302のレスポンス + URL
    上で指定されたURLへの
    リクエスト
    レスポンス

    View Slide

  90. 90
    ▸ POSTをした後にブラウザバックをするとPOSTをし直してしまうのを防ぐことができる。
    ▸ HttpServletResponse#sendRedirect(String)を使うことでリダイレクトすることができる。
    (補足)リクエストのリダイレクト

    View Slide

  91. 91
    複数のServletの前処理、後処理を行う。(HttpFilter)
    複数のServletに対して共通の前処理、後処理を埋め込む。
    一律で認証を行う、ログを出力する場合等に使用される。
    クライアント ②Servlet
    ①HttpServletRequest
    ③HttpServletResponse
    共通の
    前処理
    後処理

    View Slide

  92. 92
    HttpFilterの関連クラス
    HttpFilter
    GenericFilter
    <>
    Filter

    View Slide

  93. 93
    HttpFilterの関連クラス
    HttpFilter
    GenericFilter
    <>
    Filterd
    HTTPプロトコルに依存しない汎用のフィルター
    HTTPプロトコル用のフィルター
    コンテナからみた汎用の
    フィルターインターフェース

    View Slide

  94. 94
    HttpFilterの実装例
    ▸ @WebFilterアノテーションを付けてHttpFilterをextendsして実装する。

    View Slide

  95. 95
    Filterの説明
    ▸ 1つのServlet、URLに対して複数のFilterを登録することができる。
    ▸ アノテーションを使用して登録する場合、複数のFilterの実行される順序は指定できない。
    ▸ すべてのFilterを通るとServletが実行され、Servletの実行が終わるとFIlterに処理が返ってくる。
    ・ 処理Stackの底にServletが居て、上にFilterが積もってる感じ。
    ▸ @WebFilterアノテーションではURLのほかに処理するServletを指定することもできる。
    ・ ほぼ@WebServletアノテーションと一緒。

    View Slide

  96. 96
    動的なServlet、Filterの登録
    ▸ アプリケーション(コンテキスト)の起動時に動的にServlet、Filterを登録することができる。
    ・ その場合、Servlet、Filterの実装クラスにはアノテーションを付けない。
    ▸ 複数のアプリケーションサーバーで動かしたい場合に、アプリケーションサーバー間の非互換を
    緩和するために違ったFilterを登録して前処理を行うことがある。
    ▸ この機能でFilterを登録する場合はFilterの実行順序を制御することができる。

    View Slide

  97. 97
    動的なServlet、Filterの登録
    ▸ 以下の二つのクラスのメソッド内でのみ登録できる。
    ・ ServletContextListener#contextInitialized(ServletContextEvent)
    ・ アプリケーション(コンテキスト)の起動、終了を検知するリスナー。
    ・ ServletContainerInitializer#onStartup(Set>,ServletContext)
    ・ WEB-INF/libの配下のjarでServiceLoaderを使用して実行される。
    ・ ServletContextListenerより先に実行される。

    View Slide

  98. 98
    動的なServlet、Filterの登録例

    View Slide

  99. 99
    Servletのセキュリティ
    ▸ 認証、認可のための仕様が規定されている。
    ・ が、本体はJakarta Authorizationで定義されていて、Servletの範囲でだけ知っても意味がな
    いので、意味がありそうな範囲(ログイン、ログアウトで行わないといけないこと)だけ。

    View Slide

  100. 100
    Servletのセキュリティ – ログイン
    ▸ ログイン成功後にHttpServletRequest#changeSessionId()を呼びだす必要がある。
    ・ セッション固定化攻撃を防ぐため。
    ・ ログイン処理を独自実装している場合も呼んでね。
    try {
    httpServletRequest.login(“user”,“password”); //ログイン試行
    httpServletRequest.changeSessionId(); // セッションIDを変更する。
    } catch(ServletException ex) {
    // failed.
    }

    View Slide

  101. 101
    Servletのセキュリティ – ログアウト
    ▸ セッションの無効化=ログアウトではない場合がある。
    ・ Jakarta EE 10ではSSOへの対応が標準化されたため、セッションの無効化だけではログアウ
    トが他サーバーに連携されず問題となる可能性が。
    ▸ HttpServletRequest#logout()をログアウト時に呼び出す必要がある。
    httpServletRequest.logout(); //ログアウト
    httpServletRequest.getSession().invalidate(); //セッション無効化

    View Slide

  102. 102
    その他のServletの仕様
    説明していないものとか説明が足りていないものとか・・・・
    ▸ 同期、非同期処理、スレッド等
    ▸ 通信のアップグレード(websocket)
    ▸ 国際化
    ▸ web-fragment.xmlを利用したモジュール化
    ▸ Servletコンテナのライフサイクル
    ▸ 例外処理
    ▸ その他・・・・・

    View Slide

  103. Servlet 4.0(Java EE 8)以降
    Servlet
    非互換・新機能
    (5/5)
    103

    View Slide

  104. 104
    Springが長らくJava EE 7(Servlet 3.1)で止まっていたので、それ以降の主な非互換・新機能。
    この資料を書いた人の心に残ったものを抜粋。
    Servlet非互換・新機能

    View Slide

  105. 105
    ▸ サーブレットがどうやって呼び出されたのか(どのURLにマッチしたのか)を返してくれる。
    ▸ HttpServletRequest#getHttpServletMapping()
    ▸ 任意のURL(*)でマッチさせてフレームワーク側でURLを解析して個々の機能を実行する場
    合に便利
    Servlet新機能 – HttpServletMapping (4.0)

    View Slide

  106. 106
    ▸ 今までFilterインターフェースしかなかったのがServletに合わせてGenericFilter、HttpFilter
    が作成された。
    ・ 今後はFilterインターフェースを直接使う必要はない。
    Servlet新機能 – HttpFilter (4.0)

    View Slide

  107. 107
    ▸ web.xmlにrequest-character-encoding 、response-character-encoding が追加された。
    ▸ ServletContextにも上記に対応するメソッドが追加。
    ▸ 今まではリクエスト/レスポンス単位もしくはコンテナ側の実装依存でしか指定が出来なか
    った。
    ・ 未指定だとISO-8859-1(ラテン文字のみで日本語非対応)になるのでUTF-8を指定する
    のが無難。
    Servlet新機能 –文字コード指定の標準化 (4.0)

    View Slide

  108. 108
    ▸ HttpリクエストやHttpレスポンスのボディの後に含まれることのあるトレーラーフィール
    ドにアクセスできるようになった。
    ▸ 詳細についてはHttpServletRequest/HttpServletResponseのJavaDocを参照。
    Servlet新機能 –トレーラーフィールド (4.0)

    View Slide

  109. 109
    ▸ Eclipseファウンデーションへの移管に伴いパッケージ名が変更された。
    ▸ Servlet内でExceptionが発生してコンテナ側で検知したときに入れるエラーのキーやSSLの
    値等、ServletRequest#getAttribute()でとれるいくつかの属性が変更に。
    ▸ コンパイルエラーだけを気にしていると発見できない可能性があるので注意。
    例)Javax.servlet.request .error.status_code-> jakarta.servlet.error.status_code
    Servlet非互換 – javax -> jakartaへの変更 (5.0)

    View Slide

  110. 110
    ▸ Deprecatedに指定されていたクラス、メソッドが除去された。
    ▸ これにより既存機能が動かなくなってる可能性があるので注意。
    Servlet非互換 - 非推奨クラス、メソッドの除去 (6.0)

    View Slide

  111. 111
    ▸ Cookieクラスに自由に属性を入れられるようになった。
    ・ Cookie#setAttribute(String name, String value)
    ▸ HTTPのCookieの仕様が更新されて属性が追加されてもServlet APIで新しい属性が使える
    ようになるまでに時間がかかっていたのが解消。
    ・ 使いたい場合、Cookieクラスを使わずに直接レスポンスヘッダーに書き込んでいた。
    Servlet新機能 – Cookie (6.0)

    View Slide

  112. 112
    ▸ HttpServletのデフォルト実装ではもともとはdoGetを実行しつつheaderだけを返していた。
    ▸ 今後はdoGetと処理が同じになる。
    Servlet非互換 - doHeadのデフォルト実装変更(6.0)

    View Slide

  113. 113
    ▸ Servlet Specificationのページに変更点が載ってますので、そちらを参照してください!
    https://jakarta.ee/specifications/servlet/6.0/
    その他の変更点について

    View Slide

  114. linkedin.com/company/red-hat
    youtube.com/user/RedHatVideos
    facebook.com/redhatinc
    twitter.com/RedHat
    Red Hat is the world’s leading provider of
    enterprise open source software solutions. Award-
    winning support, training, and consulting services
    make
    Red Hat a trusted adviser to the Fortune 500.
    Thank you
    114

    View Slide