Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

はじめに(1/5) 4

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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の始まり

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

HTTP(2/5) 11

Slide 12

Slide 12 text

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の薄いラッパー

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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リクエストの例 ヘッダー 空行 メッセージボディ リクエストライン

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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リクエスト-ヘッダー-主なヘッダー

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

32 例)

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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の生成

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

Servlet (3/5) 45

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

56 (参考) Tomcatのバージョンごとのweb.xmlのヘッダー https://megascus.hatenablog.com/entry/20180418/1524034199 (参考)Jakarta Servlet 6.0バージョンのヘッダー

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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リクエストの例 ヘッダー 空行 メッセージボディ リクエストライン

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

78 ▸ web.xmlにerror-pageタグを追加する。 例) 404 /path/to/servlet ※locationにはservlet以外に静的ファイル等も指定可能。 ▸ 処理を呼び出す側では HttpServletResponse#sendError(int)を呼び出す。 ※引数はHTTPステータスコード。 特定のステータスコード時の処理を共通化する

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

98 動的なServlet、Filterの登録例

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

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

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

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