$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. 2 ▸ 名前:瀬戸 智 ▸ Twitter: @megascus ▸ Servletを使い始めたのは2005年から。 ▸

    ServletとかJPAあたりが好きで、一時期個人でServletとJPAのJavaDocを翻訳していた。 ・ そのあとPleiadesの人が機械翻訳をしてくれるようになったので現時点では意味なし。 自己紹介
  2. 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の始まり
  3. 8 ▸ 当時(1990年代)はCGIが全盛。 ・ CGI=Commmon Gateway Interface ・ ウェブサーバーが外部クライアントからのリクエストを受けてプログラム(プロセス)を起動 し、その結果をクライアントに返す仕組み。

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

    once, run anywhere. ▸ 複数のリクエストを軽量に同時に処理できる。(=マルチスレッド) =Javaでやりたいこと。 Servletのやりたいこと
  5. 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の薄いラッパー
  6. 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
  7. 14 ▸ HTTP=HyperText Transfer Protocolの略称。 ▸ 名前の通りテキストをやり取りするための仕様。 ▸ リソースはhttp://から始まるURL(もしくはURI)であらわされる。 ・

    URLの例 http://www.example.com/context/file?param1=value1&param2=value2 ▸ クライアントはURLを使用してサーバーにアクセスし、レスポンスを受け取る。 HTTPとは
  8. 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リクエストの例 ヘッダー 空行 メッセージボディ リクエストライン
  9. 17 例) POST /xxxx/yyyyy HTTP/1.1 ▸ メソッド名 ←この次に説明 ▸ アクセスする先のリソースのパス

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

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

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

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

    ・ MIME(Multipurpose Internet Mail Extensions)の一種。 ※HTTPはバイナリデータをやり取りするのには向かない方式なので、ファイルのやり取りを するのが主目的の場合は別の方式を検討したほうが良いです。 base64でエンコードされたメッセージボディ
  15. 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レスポンスの例 ヘッダー 空行 メッセージボディ ステータスライン
  16. 26 例) HTTP/1.1 200 OK ▸ HTTPのバージョン ・ だいたい HTTP/1.1

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

    ・ 200番台 リクエストは受け取られて、理解されて、処理された。 ・ 300番台 リクエストを処理するために、ほかのリソースへのアクセスを必要とする。 ・ 400番台 クライアント側のリクエストにエラーがあり処理できなかった。 ・ 500番台 サーバー側で処理に失敗した。 HTTPレスポンス-ステータスライン-ステータスコード
  18. 28 ▸ 200 OK リクエストに成功され正常に処理された。 ▸ 301 Moved Permanently リソースが恒久的に他のURLに移動した

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

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

    ” + VALUE の形式 ▸ レスポンスの付帯情報を表す。 ▸ 大文字、小文字は区別されない。 ▸ 決められたものがいくつかあるが、任意のものを追加可能。 HTTPレスポンス-ヘッダー
  21. 31 ▸ Content-Type: text/html; charset=Shift_JIS ・ ファイルのコンテンツタイプ ▸ Date: Wed,

    16 Nov 2022 09:23:34 GMT ・ リソースの更新日時 ▸ Cache-Control: private, max-age=0 ・ コンテンツをキャッシュしてよいかどうか HTTPレスポンス-ヘッダー-主なヘッダー
  22. 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の生成
  23. 43 ▸ HTTPS = HyperText Transfer Protocol Secure ▸ httpは平文でやり取りをするがhttpsは暗号化してやり取りを行う。

    ▸ 最近はhttp通信は極力なくし、すべてをhttpsにしたほうが良いと言われている。 (参考)その他のHTTP : HTTPS
  24. 48 ▸ 複数のユーザー作成のアプリケーションを動作させることができる(場合もある) ▸ 複数のアプリケーションを安定して動作できるように相互のアプリケーションは分離され ている。 ▸ コンテナが安定して動作できるようにアプリケーションからコンテナは操作ができないよ うになっている。 ・

    コンテナ側からユーザー作成のクラスを参照する事は制限されている。 ・ アプリケーションに含まれるクラスでコンテナ側のクラスを上書きできると、 ユーザーアプリケーションがコンテナの動作を自由に変更できることになるので困る。 Servletコンテナの特徴
  25. 50 AppRoot │ file1 ← 外部からアクセスされる可能性のあるファイル │ file2 ・・・ ├─META-INF

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

    ▸ /WEB-INF/classes/ アプリケーションの実行に必要なclassファイルが含められる。 ▸ /WEB-INF/lib/ アプリケーションの実行に必要なライブラリ:jarが含められる。 これらのディレクトリの内部は外部から直接参照する事ができない。 ※WebJarsはjsやcss等のファイルを圧縮してjarに固めたもの。 アプリケーションのディレクトリ構造
  27. 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
  28. 57 ▸ HttpServlet ・ サーバー側での処理を実装するクラス ・ 実際の処理をこれのサブクラスとして実装する。 ▸ HttpServletRequest ・

    クライアントからのリクエストを表すクラス ▸ HttpServletResponse ・ クライアントへのレスポンスを表すクラス Servlet APIでコアとなる3クラス
  29. 68 Servletをコンテナに登録するために使用する。web.xmlに同等の事を記載することができる。 ▸ name – Servletの名前を付ける。(管理用) ▸ urlPatterns (必須) –

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

    ▸ #getHeader(String) –キーを指定してヘッダーの値を取得する。 ▸ #getPrameter(String) –キーを指定してリクエストパラメーターの値を取得する。 リクエストパラメーターはURLの一部(?の後の&で連結されたkey=value、もしくはメッセ ージボディに入ってくる&で連結されたkey=value) HttpServletRequest
  32. 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レスポンスの例 ヘッダー 空行 メッセージボディ ステータスライン
  33. 73 クライアントへのレスポンスを表したもの。以下のようなメソッドがある。 ▸ #setStatus(int) – レスポンスのステータスコードを指定する。 ▸ #setHeader(String, String) -

    ヘッダーの値を指定する。#setContentType()等、よく知ら れたヘッダーに対応するメソッドも存在する。 ▸ #getWriter() / #getOutputStream() - レスポンスボディに書き込むためのWriter / OutputStreamを取得する。テキストかバイナリデータかで使い分ける必要がある。どちら かしか取得できず、両方を呼び出すと例外が発生する。 HttpServletResponse
  34. 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ステータスコード。 特定のステータスコード時の処理を共通化する
  35. 79 ▸ HttpServletRequest#getRequestDispatcher(String)を呼び出して取得した RequestDispatcherを使用する。 ※引数は他のServletへのPATH ▸ RequestDispacherではさらに以下のメソッドを呼び出して他のServletの処理を実行する。 ・ #include() –

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

    同じユーザーからのリクエストを処理するときに複数 のリクエストの間で共有できるスコープ ▸ アプリケーション(コンテキスト)スコープ(ServletContext) – アプリケーション内全体で共 有できるスコープ 複数のServletでのデータの受け渡し(スコープ)
  37. 87 ▸ それぞれのスコープへの書き込み、読み込み、削除を感知できるリスナー。 ▸ インターフェースを実装したうえで@WebListenerアノテーションを付ける。 ▸ 詳細はJavaDocを参照のこと。 ・ jakarta.servlet.ServletRequestAttributeListener –

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

    アプリケーションの起動、終了 ・ jakarta.servlet.ServletRequestListener – リクエストの受付、返送 ・ jakarta.servlet.http.HttpSessionIdListener – セッションの有効化、無効化 ・ ログイン時ではないので注意! (補足)そのほかのリスナー
  39. 100 Servletのセキュリティ – ログイン ▸ ログイン成功後にHttpServletRequest#changeSessionId()を呼びだす必要がある。 ・ セッション固定化攻撃を防ぐため。 ・ ログイン処理を独自実装している場合も呼んでね。

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

    トが他サーバーに連携されず問題となる可能性が。 ▸ HttpServletRequest#logout()をログアウト時に呼び出す必要がある。 httpServletRequest.logout(); //ログアウト httpServletRequest.getSession().invalidate(); //セッション無効化
  41. 111 ▸ Cookieクラスに自由に属性を入れられるようになった。 ・ Cookie#setAttribute(String name, String value) ▸ HTTPのCookieの仕様が更新されて属性が追加されてもServlet

    APIで新しい属性が使える ようになるまでに時間がかかっていたのが解消。 ・ 使いたい場合、Cookieクラスを使わずに直接レスポンスヘッダーに書き込んでいた。 Servlet新機能 – Cookie (6.0)
  42. 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