$30 off During Our Annual Pro Sale. View Details »

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仕様勉強会

  2. 2 ▸ 名前:瀬戸 智 ▸ Twitter: @megascus ▸ Servletを使い始めたのは2005年から。 ▸

    ServletとかJPAあたりが好きで、一時期個人でServletとJPAのJavaDocを翻訳していた。 ・ そのあとPleiadesの人が機械翻訳をしてくれるようになったので現時点では意味なし。 自己紹介
  3. 3 ▸ はじめに ▸ HTTP ▸ Servlet ▸ Servletの高度な機能 ▸

    Servlet 非互換・新機能 アジェンダ
  4. はじめに(1/5) 4

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

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

  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の始まり
  8. 8 ▸ 当時(1990年代)はCGIが全盛。 ・ CGI=Commmon Gateway Interface ・ ウェブサーバーが外部クライアントからのリクエストを受けてプログラム(プロセス)を起動 し、その結果をクライアントに返す仕組み。

    ▸ CGIは移植性に問題があり、各OSでプログラムを実装しなおす必要があった。 ・ C言語とかでOSごとに実装しなおす。 ▸ 当時の貧弱なPCだとプログラム(プロセス)の起動のオーバーヘッドが大きかった。 ・ プログラムを常駐させて繰り返しリクエストを処理することでプロセス起動の負荷を下げ て、より多くの処理を行えるのではないだろうか? Servletの始まり
  9. 9 ▸ 低負荷のHTTPサーバーを実装する。 ・ Javaアプリを常駐させることで負荷を軽減する。 ▸ どこでも動くようにする。 ・ いわゆる Write

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

  11. HTTP(2/5) 11

  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の薄いラッパー
  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
  14. 14 ▸ HTTP=HyperText Transfer Protocolの略称。 ▸ 名前の通りテキストをやり取りするための仕様。 ▸ リソースはhttp://から始まるURL(もしくはURI)であらわされる。 ・

    URLの例 http://www.example.com/context/file?param1=value1&param2=value2 ▸ クライアントはURLを使用してサーバーにアクセスし、レスポンスを受け取る。 HTTPとは
  15. 15 HTTPとは 1対1でリクエストに対してサーバーが処理をしてレスポンスを返す。これだけ。※例外アリ クライアント ②サーバーが 処理をする ①リクエスト(Request、要求) を投げる ③レスポンス(Response、応答) を受け取る

  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リクエストの例 ヘッダー 空行 メッセージボディ リクエストライン
  17. 17 例) POST /xxxx/yyyyy HTTP/1.1 ▸ メソッド名 ←この次に説明 ▸ アクセスする先のリソースのパス

    ▸ HTTPのバージョン ・ だいたい HTTP/1.1 か HTTP/1.0 (あまり気にしなくてもよいので省略) HTTPリクエスト-リクエストライン
  18. 18 ▸ GET、HEAD、POST、OPTIONS、PUT、DELETE、TRACE、PATCH、LINK、UNLINKが ある。 ▸ サーバー上のリソースに対してどういう操作を行うか。 ▸ GETならこういう操作をしてほしいというのは定義されているが、実際にサーバー側で何 を行うのかは実装次第。実装されていない場合もある。主な仕様は以下の通り。 ・

    GET - サーバー上のリソースの内容を返す。 ・ HEAD - GETと同じだが、レスポンスヘッダーのみを返す。 ・ POST - サーバー上にフォームデータを送り処理をする。 HTTPリクエスト-リクエストライン-メソッド
  19. 19 例) Host: www.example.com ▸ KEY-VALUE形式のメタデータ。 ・ KEY + “:

    ” + VALUE の形式 ▸ リクエストの付帯情報を表す。 ▸ 大文字、小文字は区別されない。 ▸ 決められたものがいくつかあるが、任意のものを追加可能。 HTTPリクエスト-ヘッダー
  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リクエスト-ヘッダー-主なヘッダー
  21. 21 例) param1=value1&param2=value2 ▸ メッセージ本体、ペイロード本体、エンティティ本体とも呼ばれる。(本体=Body) ▸ GET、HEADメソッドの場合は使用できない。(サーバー側では無視されるべき。) ・ GET、HEADでパラメーターを使用したい場合はURLにくっつける。 ▸

    この例はリクエストパラメーター(=フォームで入力されたデータ)が送られている場合。 ・ これ以外にはbase64でエンコードされたバイナリデータが送られる場合が多い。 HTTPリクエスト-メッセージボディ
  22. 22 ▸ Base64はバイナリデータをテキストに直す方式。 ・ だいたい元のデータから33%~35%ぐらい増える。 ▸ HTTPはテキストのやり取りの取り決めなので、バイナリデータを渡す場合は文字列への 変換が必要になる。 ・ もともとはメールでよく使われている方式だったがHTTPでも採用された。

    ・ MIME(Multipurpose Internet Mail Extensions)の一種。 ※HTTPはバイナリデータをやり取りするのには向かない方式なので、ファイルのやり取りを するのが主目的の場合は別の方式を検討したほうが良いです。 base64でエンコードされたメッセージボディ
  23. 23 ▸ 30Mのファイルサイズまでしかアップロードできないようにしようと考えてリクエストサ イズを30Mで制限したら、実際には20M強までしかアップロードできなくなってしまった。 ▸ base64エンコードされるとサイズが増えるのとヘッダーの分があるため41Mぐらいで制限 するのが正しい。(30M * 1.35+α) (補足)base64が起因となるよくある事故

  24. 24 ▸ メッセージボディの後ろにつけられるkey-value形式のフィールド ・ ヘッダーに transfer-Encoding: chunkedが付いている場合のみ使用できる。 ▸ ファイルアップロード時にCRCを計算して付けておくとか、利用方法が思いつくけど、実 際に使用されている例は見たことがない。

    ・ 使用例知ってたら教えてください。 ▸ HTTPレスポンスのメッセージボディの後にも付けられる。 (補足)HTTPリクエスト-トレーラーフィールド
  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 <!doctype html><h~ HTTPレスポンスの例 ヘッダー 空行 メッセージボディ ステータスライン
  26. 26 例) HTTP/1.1 200 OK ▸ HTTPのバージョン ・ だいたい HTTP/1.1

    か HTTP/1.0 (あまり気にしなくてもよいので省略) ▸ ステータスコード ←この後説明 ▸ ステータスの理由 ・ サーバー側が自由に設定できるステータスコードの詳細な理由 HTTPレスポンス-ステータスライン
  27. 27 ▸ レスポンスの状態コードを表す3桁の整数コード。 例)418 ▸ クライアントからのリクエストをサーバーがどのように解釈して結果としてどういう処理 が行われたのかを返す。一番上の数字で大まかな理由がわかる。 ・ 100番台 リクエストは受け取られ、処理は継続されている。

    ・ 200番台 リクエストは受け取られて、理解されて、処理された。 ・ 300番台 リクエストを処理するために、ほかのリソースへのアクセスを必要とする。 ・ 400番台 クライアント側のリクエストにエラーがあり処理できなかった。 ・ 500番台 サーバー側で処理に失敗した。 HTTPレスポンス-ステータスライン-ステータスコード
  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 サーバー内部のプログラムでエラーが発生した よくあるステータスコード
  29. 29 301 Moved Permanently リソースが恒久的に他のURLに移動した 307 Temporary Redirect 一時的なリダイレクト ▸

    307を返すべきところで、301を返してしまい、2度とアクセスできなくなることがある。 ▸ 一般的にHTTPクライアント(ブラウザ)は301が返されたリソースは301が返されたことを記 憶し、キャッシュが有効な限りは2度とアクセスしに行かない。 (補足)301と307の使い分けに注意!
  30. 30 例) Host: www.example.com ▸ KEY-VALUE形式のメタデータ。 ・ KEY + “:

    ” + VALUE の形式 ▸ レスポンスの付帯情報を表す。 ▸ 大文字、小文字は区別されない。 ▸ 決められたものがいくつかあるが、任意のものを追加可能。 HTTPレスポンス-ヘッダー
  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レスポンス-ヘッダー-主なヘッダー
  32. 32 例) <!doctype html><h~ ▸ サーバーにアクセスして取得した実コンテンツ。 ▸ 複数ファイルを返すことも可能。(今回は説明しません) ▸ バイナリデータの場合はbase64でエンコードされる。(のでレスポンスサイズが増える)

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

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

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

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

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

  39. 39 ▸ HTTPの仕組みには存在しない。 ▸ Cookieを使って同じユーザーからのリクエストを特定し、ユーザーの情報をサーバー側で 保持する。 ・ Cookieを使わない方式もあるけどほぼ使われないので省略。 例) Set-Cookie:

    jsessionid=8315ba76-6604-11ed-bb8d-00155daa0717 Session(セッション)
  40. 40 ▸ 自分でも簡単に実装はできるが、実装しないでください。 ▸ アプリケーションサーバーの多くではデフォルトで機能としてついている、もしくはオプ ションで機能があります。 ▸ 自分で実装する場合セキュリティ上のリスクとなる可能性があります。 ・ セッションを特定するための文字列が単純で第三者が推測できることによるセッショ

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

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

    QUIC
  43. 43 ▸ HTTPS = HyperText Transfer Protocol Secure ▸ httpは平文でやり取りをするがhttpsは暗号化してやり取りを行う。

    ▸ 最近はhttp通信は極力なくし、すべてをhttpsにしたほうが良いと言われている。 (参考)その他のHTTP : HTTPS
  44. 44 ▸ HTTPはテキストでやり取りをする。 ・ バイナリデータのやり取りには非効率。 ▸ Cookieでサーバーの情報をクライアント側に保存できる。 ・ ユーザーは自由に変更することができる。 ▸

    SessionはHTTPの仕組みではない。 ・ セキュリティ上の問題となるので自分では実装しないこと。 ここまでのまとめ
  45. Servlet (3/5) 45

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

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

    ・ Spring-Boot(組み込みTomcat)とか Servletコンテナ
  48. 48 ▸ 複数のユーザー作成のアプリケーションを動作させることができる(場合もある) ▸ 複数のアプリケーションを安定して動作できるように相互のアプリケーションは分離され ている。 ▸ コンテナが安定して動作できるようにアプリケーションからコンテナは操作ができないよ うになっている。 ・

    コンテナ側からユーザー作成のクラスを参照する事は制限されている。 ・ アプリケーションに含まれるクラスでコンテナ側のクラスを上書きできると、 ユーザーアプリケーションがコンテナの動作を自由に変更できることになるので困る。 Servletコンテナの特徴
  49. 49 ▸ ユーザーが作成する処理の塊の単位。コンテキストとも呼ばれる。 ▸ アプリケーションは特定の構造をもったディレクトリ、もしくはそれをzipで固めて拡張子 をwar(Web ARchive)としたもの、のどちらかになる。 ・ アプリケーションサーバーによってはどちらかしか受け付けない場合もある。 (ユーザーの)アプリケーション

  50. 50 AppRoot │ file1 ← 外部からアクセスされる可能性のあるファイル │ file2 ・・・ ├─META-INF

    └─resources └─WEB-INF │ web.xml (ファイル) ├─classes └─lib アプリケーションのディレクトリ構造
  51. 51 ▸ /META-INF/ アプリケーションのメタ情報が含められる。 ▸ /META-INF/resources/ 少し前に流行ったWebJarsが含められる。 ▸ /WEB-INF/ アプリケーションの設定ファイル、実行ファイルが含められる。

    ▸ /WEB-INF/classes/ アプリケーションの実行に必要なclassファイルが含められる。 ▸ /WEB-INF/lib/ アプリケーションの実行に必要なライブラリ:jarが含められる。 これらのディレクトリの内部は外部から直接参照する事ができない。 ※WebJarsはjsやcss等のファイルを圧縮してjarに固めたもの。 アプリケーションのディレクトリ構造
  52. 52 ▸ プログラム経由で見られるべきViewのテンプレートファイルがWEB-INFもしくはMETA- INFの外側に置かれていて、直接実行できてしまう。 ▸ 当然権限制御等はされていないので、見られてはいけないものが外部に公開されている。 ▸ ロジックが実行されてから表示されることが前提とされているものの、ロジックが実行さ れていないので、サーバーエラーとしてログに記録され緊急対応が必要になる。 ・

    直接参照されたくないファイルはすべてWEB-INFの下に置くか、別の方法でアクセス 制御を行いましょう。 (補足)よくある事故
  53. 53 複数のアプリケーションがサーバーにデプロイされている場合は、デフォルトではURLのホス トの一階層下のパスでどのアプリケーションがリクエストを処理するべきかが判断される。 一般的にコンテキストパスと呼ばれる。 コンテキストパスが空(=ルートコンテキスト)の場合もある。 http://www.example.com/context/path/to/servlet 複数のアプリケーション

  54. 54 ▸ Servletコンテナの設定ファイル ▸ 以前はこのファイルが必須だったが、現時点では必須ではない。 ▸ この後いくつかの設定の説明をアノテーションを使って行うが、同等の事をすべて web.xmlに記載することができる。 ▸ Servlet仕様ではデフォルトでリクエスト、レスポンスがISO

    8859-1(ラテン文字のみ)で扱 われるので、UTF-8にする設定を入れる必要があるかもしれない。 <request-character-encoding>UTF-8</request-character-encoding> <response-character-encoding>UTF-8</response-character-encoding> /WEB-INF/web.xml
  55. 55 ▸ 動いているサーブレットコンテナで使われているServletのバージョンと、web.xmlのヘッ ダーのバージョンが一致してる必要がある。 ・ 一致していない場合は一部機能が使えない場合がある。 ▸ 古いアプリケーションを最新のアプリケーションサーバーに移植している場合は更新漏れ に注意! (注意)web.xmlのヘッダーについて

  56. 56 <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" 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バージョンのヘッダー
  57. 57 ▸ HttpServlet ・ サーバー側での処理を実装するクラス ・ 実際の処理をこれのサブクラスとして実装する。 ▸ HttpServletRequest ・

    クライアントからのリクエストを表すクラス ▸ HttpServletResponse ・ クライアントへのレスポンスを表すクラス Servlet APIでコアとなる3クラス
  58. 58 HttpServletの関連クラス HttpServlet GenericServlet <<interface>> Servlet

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

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

    (補足)GenericServlet
  61. 61 ▸ HTTP用のリクエスト、レスポンスを表すインターフェース。 ・ サーブレットコンテナによって実体が生成される。 ▸ 汎用プロトコル用のServletRequest 、ServletResponse も存在する。 ・

    GenericServletと同じ理由であまり気にしなくてよい。 HttpServletRequest、HttpServletResponse
  62. 62 HttpServletに存在して、最初に意識しなければいけないメソッドは以下の通り ▸ ServletコンテナによってServletが起動するときに呼び出されるinit() ▸ ServletコンテナによってServletが終了するときに呼び出されるdestroy() ▸ HTTPリクエストを受け付けたときに起動されるservice() ▸ service()からHTTPメソッドによって分岐するdoGet()、doPost()、doHead()、doPut()、

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

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

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

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

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

  68. 68 Servletをコンテナに登録するために使用する。web.xmlに同等の事を記載することができる。 ▸ name – Servletの名前を付ける。(管理用) ▸ urlPatterns (必須) –

    どのURLでServletが起動するか。実際はアプリケーションのコンテキ ストパスの後ろの部分に紐づく。*で任意のURLを指定できる。 http://www.example.com/context/path/to/servlet ▸ loadOnStartup – Servletの実行順序、正の整数を指定するとServletコンテナの起動時に数 字の小さい順に起動する。(指定しない場合はいつ起動するかは不定。通常は初回アクセス 時。) @WebServletの概要(とよく使う属性)
  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リクエストの例 ヘッダー 空行 メッセージボディ リクエストライン
  70. 70 クライアントからのリクエストを表したもの。以下のようなメソッドがある。 ▸ #getMedhod() - リクエストのメソッドを取得する。 ▸ #getRequestURL() – リクエストのURLを取得する。

    ▸ #getHeader(String) –キーを指定してヘッダーの値を取得する。 ▸ #getPrameter(String) –キーを指定してリクエストパラメーターの値を取得する。 リクエストパラメーターはURLの一部(?の後の&で連結されたkey=value、もしくはメッセ ージボディに入ってくる&で連結されたkey=value) HttpServletRequest
  71. 71 ファイルアップロードは大量のデータを扱う必要が出てくるため、扱いが特殊になっている。 ▸ Servletに@MultipartConfigアノテーションを付ける。 ・ ファイルアップロードできる最大サイズ等を指定。 ▸ HttpServletRequest#getParts()で取得できる。 (補足)ファイルアップロード

  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 <!doctype html><h~ (思い出すシリーズ)HTTPレスポンスの例 ヘッダー 空行 メッセージボディ ステータスライン
  73. 73 クライアントへのレスポンスを表したもの。以下のようなメソッドがある。 ▸ #setStatus(int) – レスポンスのステータスコードを指定する。 ▸ #setHeader(String, String) -

    ヘッダーの値を指定する。#setContentType()等、よく知ら れたヘッダーに対応するメソッドも存在する。 ▸ #getWriter() / #getOutputStream() - レスポンスボディに書き込むためのWriter / OutputStreamを取得する。テキストかバイナリデータかで使い分ける必要がある。どちら かしか取得できず、両方を呼び出すと例外が発生する。 HttpServletResponse
  74. 74 ▸ クライアントへ返すレスポンスのバッファーサイズが決められており、ボディ (Writer/OutputStream)に一定以上書き込んでからヘッダーに書き込もうとするとエラーに なる。 ・ バッファーサイズは実装依存で変更可能な場合が多い。 ▸ 何がヘッダーに書き込まれるのか意識して実装を! ▸

    サーバーサイドでの処理を完全に終了させてからHttpServletResponseへの書き込みを開始 するのが無難。(=ModelとViewの分離) (補足)HttpServletResponseへの書き込み
  75. 75 クライアント側で保存してほしいデータを送信する、取得する。 HTTP CookieをJavaで取り扱うためのCookieクラスが存在する。 ▸ HttpServletRequest#getCookies() – クライアント側から送られてきたCookieを取得する。 ▸ HttpServletResponse#addCookie(Cookie)

    – クライアント側にCookieを送信する。 ・ Cookieを削除したい場合はCookie#setMaxAge (0)を呼び出したものを送信する。 Cookieの取り扱い
  76. Servletの高度な機能 (4/5) 76

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

  78. 78 ▸ web.xmlにerror-pageタグを追加する。 例) <error-page> <error-code>404</error-code> <location>/path/to/servlet</location> </error-page> ※locationにはservlet以外に静的ファイル等も指定可能。 ▸

    処理を呼び出す側では HttpServletResponse#sendError(int)を呼び出す。 ※引数はHTTPステータスコード。 特定のステータスコード時の処理を共通化する
  79. 79 ▸ HttpServletRequest#getRequestDispatcher(String)を呼び出して取得した RequestDispatcherを使用する。 ※引数は他のServletへのPATH ▸ RequestDispacherではさらに以下のメソッドを呼び出して他のServletの処理を実行する。 ・ #include() –

    呼び出し元のクライアントへの出力をそのままにする。 ・ #forward() – 呼び出し元のクライアントへの出力をクリアする。 ※呼び出し元のServletでレスポンスに大量のデータを書き込んでいて、バッファがあふれて クライアントにレスポンスが返っていた場合にはエラーになる。 汎用的に他のServletを呼び出す
  80. 80 複数のServlet間でデータの受け渡しができるように値のスコープが定義されている。 ▸ リクエストスコープ(HttpServletRequest) – ユーザーからのリクエストが送られてきてレ スポンスが返し終わるまで有効なスコープ ▸ セッションスコープ(HttpSession) -

    同じユーザーからのリクエストを処理するときに複数 のリクエストの間で共有できるスコープ ▸ アプリケーション(コンテキスト)スコープ(ServletContext) – アプリケーション内全体で共 有できるスコープ 複数のServletでのデータの受け渡し(スコープ)
  81. 81 ユーザーからのリクエストを受け取りレスポンスを返し終わるまで有効なスコープ key-value形式で属性値(オブジェクト)を保持する。 ▸ HttpServletRequest#getAttribute(String)で値を取得。 ▸ HttpServletRequest#setAttribute(String, Object)で値を設定。 keyとしてjakarta.から始まるものは設定してはいけない。コンテナによって予約されている。 リクエストスコープ

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

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

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

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

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

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

    リクエストの属性用 ・ jakarta.servlet.http.HttpSessionAttributeListener – セッションの属性用 ・ jakarta.servlet.ServletContextAttributeListener – アプリケーション(コンテキスト)の 属性用 スコープのAttribute(属性)のリスナー
  88. 88 ▸ 属性のリスナーのほかに以下のリスナーが存在する。 ▸ インターフェースを実装したうえで@WebListenerアノテーションを付ける。 ▸ 詳細はJavaDocを参照のこと。 ・ jakarta.servlet.ServletContextListener –

    アプリケーションの起動、終了 ・ jakarta.servlet.ServletRequestListener – リクエストの受付、返送 ・ jakarta.servlet.http.HttpSessionIdListener – セッションの有効化、無効化 ・ ログイン時ではないので注意! (補足)そのほかのリスナー
  89. 89 (参考)リクエストのリダイレクト サーバーサイドでステータスコード302を投げることで、クライアントに別のURLへのリクエスト のし直しを指示することができる。この場合、サーバーサイドでは複数のリクエストとして処理さ れるので、リクエストスコープでは値を引き継げない。 クライアント ②Servlet リクエスト 302のレスポンス +

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

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

    後処理
  92. 92 HttpFilterの関連クラス HttpFilter GenericFilter <<interface>> Filter

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

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

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

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

    この機能でFilterを登録する場合はFilterの実行順序を制御することができる。
  97. 97 動的なServlet、Filterの登録 ▸ 以下の二つのクラスのメソッド内でのみ登録できる。 ・ ServletContextListener#contextInitialized(ServletContextEvent) ・ アプリケーション(コンテキスト)の起動、終了を検知するリスナー。 ・ ServletContainerInitializer#onStartup(Set<Class<>>,ServletContext)

    ・ WEB-INF/libの配下のjarでServiceLoaderを使用して実行される。 ・ ServletContextListenerより先に実行される。
  98. 98 動的なServlet、Filterの登録例

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

  100. 100 Servletのセキュリティ – ログイン ▸ ログイン成功後にHttpServletRequest#changeSessionId()を呼びだす必要がある。 ・ セッション固定化攻撃を防ぐため。 ・ ログイン処理を独自実装している場合も呼んでね。

    try { httpServletRequest.login(“user”,“password”); //ログイン試行 httpServletRequest.changeSessionId(); // セッションIDを変更する。 } catch(ServletException ex) { // failed. }
  101. 101 Servletのセキュリティ – ログアウト ▸ セッションの無効化=ログアウトではない場合がある。 ・ Jakarta EE 10ではSSOへの対応が標準化されたため、セッションの無効化だけではログアウ

    トが他サーバーに連携されず問題となる可能性が。 ▸ HttpServletRequest#logout()をログアウト時に呼び出す必要がある。 httpServletRequest.logout(); //ログアウト httpServletRequest.getSession().invalidate(); //セッション無効化
  102. 102 その他のServletの仕様 説明していないものとか説明が足りていないものとか・・・・ ▸ 同期、非同期処理、スレッド等 ▸ 通信のアップグレード(websocket) ▸ 国際化 ▸

    web-fragment.xmlを利用したモジュール化 ▸ Servletコンテナのライフサイクル ▸ 例外処理 ▸ その他・・・・・
  103. Servlet 4.0(Java EE 8)以降 Servlet 非互換・新機能 (5/5) 103

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

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

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

  107. 107 ▸ web.xmlにrequest-character-encoding 、response-character-encoding が追加された。 ▸ ServletContextにも上記に対応するメソッドが追加。 ▸ 今まではリクエスト/レスポンス単位もしくはコンテナ側の実装依存でしか指定が出来なか った。

    ・ 未指定だとISO-8859-1(ラテン文字のみで日本語非対応)になるのでUTF-8を指定する のが無難。 Servlet新機能 –文字コード指定の標準化 (4.0)
  108. 108 ▸ HttpリクエストやHttpレスポンスのボディの後に含まれることのあるトレーラーフィール ドにアクセスできるようになった。 ▸ 詳細についてはHttpServletRequest/HttpServletResponseのJavaDocを参照。 Servlet新機能 –トレーラーフィールド (4.0)

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

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

  111. 111 ▸ Cookieクラスに自由に属性を入れられるようになった。 ・ Cookie#setAttribute(String name, String value) ▸ HTTPのCookieの仕様が更新されて属性が追加されてもServlet

    APIで新しい属性が使える ようになるまでに時間がかかっていたのが解消。 ・ 使いたい場合、Cookieクラスを使わずに直接レスポンスヘッダーに書き込んでいた。 Servlet新機能 – Cookie (6.0)
  112. 112 ▸ HttpServletのデフォルト実装ではもともとはdoGetを実行しつつheaderだけを返していた。 ▸ 今後はdoGetと処理が同じになる。 Servlet非互換 - doHeadのデフォルト実装変更(6.0)

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

  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