diff --git a/docs/ja/ktor/FAQ.md b/docs/ja/ktor/FAQ.md
new file mode 100644
index 00000000..f2003d46
--- /dev/null
+++ b/docs/ja/ktor/FAQ.md
@@ -0,0 +1,156 @@
+
+
+ Ktorという名前は、略語の
+ 利用可能なサポートチャネルの詳細については、Supportページをご覧ください。
+ Ktorへの貢献方法については、How to contributeガイドに記載されています。
+
+ CIOは
+ 対応する
+ EngineMain を使用して実行している場合は、自動的に処理されます。
+ それ以外の場合は、手動で処理する必要があります。JVMの機能である
+ プロキシが適切なヘッダーを提供し、
+
+
+ Ktorはルーティングの決定に関するトラブルシューティングを支援するトレースメカニズムを提供しています。
+ Tracing routes セクションを確認してください。
+
+ これは、あなた自身、あるいはプラグインやインターセプターがすでに
+ 詳細は
+ これは、Ktorが
+ はい、Ktorのサーバーとクライアントは、少なくともNettyエンジンを使用する場合、Android 5 (API 21) 以上で動作することが確認されています。
+
+
+ 最も可能性の高い原因は、バックエンドがリバースプロキシやロードバランサーの背後にあり、その中間機器がバックエンドに対して通常のHTTPリクエストを行っていることです。そのため、Ktorバックエンド内の
+ 通常、リバースプロキシは元のリクエストに関する情報を記述するヘッダー(HTTPSであったかどうかや元のIPアドレスなど)を送信します。それらのヘッダーを解析するための
+ Curl クライアントエンジンには
+ MinGW/MSYS2 の説明に従ってインストールします。
+
+ 以下のコマンドを使用して
+ MinGW/MSYS2をデフォルトの場所にインストールした場合は、環境変数
+ NoTransformationFoundException は、受信したボディ に対して、結果の 型からクライアントが 期待する 型への適切な変換が見つからないことを表します。
+
+ リクエストの
+ 使用している特定のコンテンツタイプに対して、必要なコンテンツ変換を登録してください。
+
+ クライアント側では ContentNegotiation プラグインを使用できます。
+ このプラグインを使用すると、異なるコンテンツタイプに対してデータをシリアライズおよびデシリアライズする方法を指定できます。
+
+ 必要なプラグインがすべてインストールされていることを確認してください。不足している可能性がある機能:
+
+ コード例:
+
+ %example_name%
+
+
+ Ktor にはマルチプラットフォーム対応の非同期 HTTP クライアントが含まれており、これを使用することで
+ このチュートリアルでは、リクエストを送信してレスポンスを出力する、最初の Ktor クライアントアプリケーションの作成方法を説明します。
+
+ このチュートリアルを始める前に、IntelliJ IDEA Community または Ultimate をインストールしてください。
+
+ 既存のプロジェクトに手動で Ktor クライアントを
+ 新しい Kotlin プロジェクトを作成するには、IntelliJ IDEA を開き、以下の手順に従います。
+
+ ウェルカム画面で
+ または、メインメニューから
+
+ 右側のペインで、以下の設定を指定します。
+
+
+
+
+
+
+
+ Ktor クライアントに必要な依存関係を追加しましょう。
+
+
+ Ktor の EAP バージョンを使用するには、Space リポジトリを追加する必要があります。
+
+
+
+ クライアントの実装を追加するには、
+
+ Ktor では、クライアントは HttpClient クラスによって表されます。
+
+
+ 上記のコードを追加すると、IDE は
+ これを修正するには、
+ IntelliJ IDEA で、定義の横にある赤い電球をクリックし、
+
+ アプリケーションを実行するには、
+ IntelliJ IDEA で、
+ IDE の下部にある
+ サーバーは
+ これで、動作するクライアントアプリケーションが作成されました。ただし、この警告を修正し、ロギングを使用して HTTP 呼び出しをデバッグできるようにするには、追加の手順が必要です。
+
+ Ktor は JVM 上のロギングに SLF4J 抽象化レイヤーを使用しているため、ロギングを有効にするには Logback などの ロギングフレームワークを提供 する必要があります。
+
+
+
+ IntelliJ IDEA で、再実行ボタン (
+ エラーが表示されなくなり、IDE 下部の
+ これでロギングが有効になりました。ログの表示を開始するには、ロギング構成を追加する必要があります。
+
+ IntelliJ IDEA で、再実行ボタン (
+
+ この構成をより深く理解し拡張するために、
+ コード例:
+
+ %example_name%
+
+
+ Server-Sent Events (SSE) は、サーバーが HTTP 接続を介してクライアントにイベントを継続的にプッシュできるようにする技術です。これは、クライアントがサーバーに対して繰り返しポーリングを行う必要なく、サーバーがイベントベースの更新を送信する必要がある場合に特に有用です。
+
+ Ktor がサポートする SSE プラグインは、サーバーとクライアントの間に一方向の接続を作成するための簡単な方法を提供します。
+ サーバー側のサポートのための SSE プラグインの詳細については、
+
+
+
+ 必要に応じて、
+ SSEConfig
+ クラスのサポートされているプロパティを設定することで、
+ 自動再接続を有効にするには、
+
+ サーバーへの接続が失われた場合、クライアントは再接続を試みる前に、指定された
+
+ 以下の例では、SSE プラグインを HTTP クライアントにインストールし、受信フローにコメントのみを含むイベントと、
+ SSE のレスポンスは本質的にストリーミングであるため、フルボディをキャプチャすることは現実的ではありません。SSE ストリームが失敗したときにレスポンスボディを安全に取得するために、診断バッファを有効にできます。このバッファには、すでに処理されたデータのみが含まれ(ネットワークからの再読み込みは行われません)、失敗した場合のロギングやエラー分析を目的としています。
+
+ コールごとにバッファを設定することもできます。
+
+
+ 失敗した場合は、ネットワークから再読み込みすることなく、
+ クライアントの SSE セッションは
+
+ URL エンドポイントを指定するには、次の 2 つのオプションから選択できます。 オプションで、接続を設定するために以下のパラメータを使用できます。
+ ラムダ引数内では、
+
+ 以下の例では、 完全な例については、
+ client-sse を参照してください。
+
+ SSE プラグインは、サーバー送信イベントの型安全な Kotlin オブジェクトへのデシリアライズをサポートしています。この機能は、サーバーからの構造化されたデータを扱う場合に特に有用です。
+
+ デシリアライズを有効にするには、SSE アクセス関数の
+ 以下は、 完全な例については、
+ client-sse を参照してください。
+
+ 必要な依存関係:
+ コード例:
+
+ %example_name%
+
+ クライアント用のWebSocketsプラグインを使用すると、サーバーとメッセージを交換するためのWebSocketセッションを処理できます。 すべてのエンジンがWebSocketsをサポートしているわけではありません。サポートされているエンジンの概要については、制限事項を参照してください。 サーバー側のWebSocketサポートについては、 オプションで、WebSockets.Config のサポートされているプロパティを渡すことで、
+ 以下の例では、WebSocketsプラグインを20秒( クライアントのWebSocketセッションは、DefaultClientWebSocketSession インターフェースによって表されます。このインターフェースは、WebSocketフレームの送受信やセッションのクローズを可能にするAPIを公開しています。
+
+ webSocket()
+ 関数は、ブロック引数として 関数ブロック内で、指定されたパスのハンドラーを定義します。ブロック内では以下の関数とプロパティが利用可能です。
+ WebSocketフレームのタイプを確認し、それに応じて処理できます。一般的なフレームタイプは以下の通りです。
+ 以下の例では、 完全な例については、client-websockets を参照してください。
+
+
+ このトピックでは、Docker Composeの下でサーバーKtorアプリケーションを実行する方法を紹介します。ここでは、
+ データベース接続の設定チュートリアルで作成されたプロジェクトでは、データベース接続を確立するためにハードコードされた属性を使用しています。
+ PostgreSQLデータベースの接続設定を
+ これらの設定は、後で
+
+
+
+ Dockerで実行するには、アプリケーションに必要なすべてのファイルがコンテナにデプロイされている必要があります。使用しているビルドシステムに応じて、これを実現するためのさまざまなプラグインがあります。 この例では、Ktorプラグインはすでに
+ アプリケーションをDocker化(Dockerize)するには、プロジェクトのルートディレクトリに新しい
+ この例では Amazon Corretto の Docker イメージを使用していますが、以下のような他の適切な代替イメージに置き換えることもできます。
+ プロジェクトのルートディレクトリに新しい
+ 以下のコマンドを実行して、Ktorアプリケーションを含むfat JARを作成します。
+
+
+ http://localhost:8080/static/index.htmlにアクセスしてWebアプリケーションを開きます。タスクのフィルタリングと新規追加のための3つのフォーム、およびタスクのテーブルが表示されたTask Manager Clientページが表示されるはずです。
+
+ コード例:
+
+ %example_name%
+
+
+ 使用されているプラグイン:
+ この記事では、Android、iOS、Web、デスクトップの各プラットフォームで動作し、Ktorを活用してシームレスなデータ処理を行うフルスタックアプリケーションをKotlinで開発する方法を学びます。
+ このチュートリアルの終わりまでに、以下のことができるようになります:
+ これまでのチュートリアルでは、タスクマネージャーの例を使用して、
+
+ 今回は、Android、iOS、Web、デスクトップのプラットフォームを対象としたクライアントを作成し、Ktorサービスを使用して表示するデータを取得します。可能な限りクライアントとサーバー間でデータ型を共有することで、開発をスピードアップし、エラーの可能性を減らします。
+
+ これまでの記事と同様に、IDEとしてIntelliJ IDEAを使用します。環境のインストールと設定については、
+
+ Kotlin Multiplatform クイックスタート
+
+ を参照してください。
+
+ Compose Multiplatformを初めて使用する場合は、このチュートリアルを開始する前に
+
+ Compose Multiplatformを始める
+
+ チュートリアルを完了することをお勧めします。タスクの複雑さを軽減するために、単一のクライアントプラットフォームに集中することもできます。例えば、iOSを使用したことがない場合は、デスクトップまたはAndroidの開発に集中するのが賢明かもしれません。
+
+ Ktorプロジェクトジェネレーターの代わりに、IntelliJ IDEAのKotlin Multiplatformプロジェクトウィザードを使用します。
+ これにより、クライアントとサービスを追加して拡張できる基本的なマルチプラットフォームプロジェクトが作成されます。クライアントはSwiftUIなどのネイティブUIライブラリを使用することもできますが、このチュートリアルでは
+ Compose Multiplatformを使用して、すべてのプラットフォームで共通の共有UIを作成します。
+
+ ターゲットプラットフォームとして
+
+ Macを使用している場合は、
+
+
+
+ ブラウザで http://0.0.0.0:8080/ にアクセスしてアプリケーションを開きます。
+ ブラウザにKtorからのメッセージが表示されるはずです。
+
+
+
+
+
+
+
+
+ たとえば、
+
+ 次に、以下に示すように、各ターゲットプラットフォームが
+ ターゲットの実行構成を実行することで、クライアントアプリケーションを起動できます。iOSシミュレーターでアプリケーションを実行するには、以下の手順に従ってください:
+
+ iOSアプリを実行すると、バックグラウンドでXcodeを使用してビルドされ、iOSシミュレーターで起動されます。
+ アプリには、クリックで画像を切り替えるボタンが表示されます。
+
+ ボタンが初めて押されると、現在のプラットフォームの詳細がそのテキストに追加されます。これを実現するコードは
+
+ これはコンポーザブル関数であり、この記事の後半で修正します。現時点で重要なのは、これがUIを表示し、共有された
+ 生成されたプロジェクトの構造を理解したところで、タスクマネージャーの機能を段階的に追加していきましょう。
+
+ まず、モデル型を追加し、クライアントとサーバーの両方からアクセスできるようにします。
+
+
+ 同じファイル内の
+
+ 優先度を表す列挙型(enum)と、タスクを表すクラスを追加します。
+
+ 次の段階は、タスクマネージャーのサーバー実装を作成することです。
+
+ このパッケージ内に、新しい
+
+ 同じパッケージ内に、以下のクラスを含む
+
+
+ この実装は以前のチュートリアルと非常によく似ていますが、簡略化のためにすべてのルーティングコードを
+ このコードを入力してインポートを追加すると、複数のコンパイルエラーが発生します。これは、Webクライアントとの対話に必要な
+ サーバーモジュールのビルドファイル(
+
+ クライアントがサーバーにアクセスできるようにするには、Ktor Clientを含める必要があります。これには以下の3種類の依存関係が関係します:
+
+ これが完了したら、Ktor Clientの薄いラッパーとして機能する
+ 新しいパッケージの中に、クライアント設定用の新しい
+
+ IPアドレスの確認方法:
+ モバイルシミュレーターは
+ 同じ
+
+
+ サーバーを実行したまま、
+
+ Androidプラットフォームでは、アプリケーションにネットワーク権限を明示的に与え、クリアテキストでのデータの送受信を許可する必要があります。これらの権限を有効にするには、
+
+
+ デスクトップクライアントについては、コンテナウィンドウにサイズとタイトルを割り当てます。
+
+
+ 以下のいずれかの実行構成を使用して、Webクライアントを実行します:
+
+ クライアントはサーバーと通信できるようになりましたが、まだ魅力的なUIとは言えません。
+
+
+ この実装により、クライアントにいくつかの基本的な機能が備わりました。
+
+
+ 最後に、独立した
+ クライアントアプリケーション(例:Androidアプリ)を再起動します。
+ タスクをスクロールし、詳細を確認し、削除できるようになります:
+
+ クライアントを完成させるために、タスクの詳細を更新できる機能を組み込みます。
+
+ 以下に示すように、
+ これは、ダイアログボックスで
+ 同じファイル内の
+ 現在選択されているタスクを保持するための追加の状態(State)を保存しています。この値が null でない場合、
+ 最後に、
+ この記事では、Kotlin Multiplatformアプリケーションのコンテキスト内でKtorを使用しました。これで、さまざまなプラットフォームを対象とした、複数のサービスとクライアントを含むプロジェクトを作成できるようになりました。
+
+ 見てきたように、コードの重複や冗長性なしに機能を構築することが可能です。プロジェクトのすべてのレイヤーで必要とされる型は、
+
+ この種の本発には、必然的にクライアントとサーバーの両方の技術に関する知識が必要になります。しかし、Kotlin
+ Multiplatform ライブラリと
+ Compose Multiplatform を使用することで、新しく学ぶ必要がある事柄を最小限に抑えることができます。最初は単一のプラットフォームにのみ焦点を当てている場合でも、アプリケーションの需要が高まるにつれて、他のプラットフォームを簡単に追加することができます。
+
+ コード例:
+ migrating-express
+ migrating-express-ktor
+
+ このガイドでは、アプリケーションの生成や最初のアプリケーションの記述から、アプリケーションの機能を拡張するためのミドルウェアの作成まで、基本的なシナリオにおいて Express アプリケーションを Ktor へ移行する方法を見ていきます。
+
+
+ Ktor は、アプリケーションのスケルトンを生成するために以下の方法を提供しています。
+
+Ktor プロジェクトジェネレーター — Web ベースのジェネレーターを使用します。
+
+
+ Ktor CLI ツール
+ — コマンドラインインターフェースから
+
+ Yeoman ジェネレーター
+
+ — プロジェクト設定を対話的に構成し、必要なプラグインを選択します。
+
+IntelliJ IDEA Ultimate — 内蔵の Ktor プロジェクトウィザードを使用します。
+
+ 詳細な手順については、
+ このセクションでは、
+ 以下の例は、サーバーを起動し、ポート
+ 完全な例については、1_hello プロジェクトを参照してください。
+
+ Ktor では、コード内でサーバーパラメータを構成し、アプリケーションを素早く実行するために embeddedServer 関数を使用できます。
+
+ 完全な例については、1_hello プロジェクトを参照してください。
+
+ また、HOCON または YAML 形式を使用する外部構成ファイルでサーバー設定を指定することもできます。
+
+ 上記の Express アプリケーションは、
+ Ktor で各レスポンスにデフォルトの
+ このセクションでは、Express と Ktor で画像、CSS ファイル、JavaScript ファイルなどの静的ファイルを配信する方法を見ていきます。
+ メインの
+ Express では、フォルダー名を
+ 完全な例については、2_static プロジェクトを参照してください。
+
+ Ktor では、
+ 完全な例については、2_static プロジェクトを参照してください。
+
+ 静的コンテンツを配信する際、Express は次のような複数のレスポンスヘッダーを追加します。
+
+ Ktor でこれらのヘッダーを管理するには、次のプラグインをインストールする必要があります。
+
+
+
+
+
+ 完全な例については、3_router プロジェクトを参照してください。
+
+
+ 完全な例については、3_router プロジェクトを参照してください。
+
+ 次の例は、ルートハンドラーをパスごとにグループ化する方法を示しています。
+
+ Express では、
+ 完全な例については、3_router プロジェクトを参照してください。
+
+ Ktor は
+ 完全な例については、3_router プロジェクトを参照してください。
+
+ どちらのフレームワークでも、関連するルートを単一のファイルにグループ化できます。
+
+ Express は、マウント可能なルートハンドラーを作成するための
+ 完全な例については、3_router プロジェクトを参照してください。
+
+ Ktor では、
+ 完全な例については、3_router プロジェクトを参照してください。
+
+ URL パスを文字列として指定する以外に、Ktor には
+ このセクションでは、ルートパラメータとクエリパラメータへのアクセス方法について説明します。
+
+ ルート(またはパス)パラメータは、URL 内のその位置に指定された値をキャプチャするために使用される名前付きの URL セグメントです。
+
+ Express でルートパラメータにアクセスするには、
+ 完全な例については、4_parameters プロジェクトを参照してください。
+
+ Ktor では、ルートパラメータは
+ 完全な例については、4_parameters プロジェクトを参照してください。
+
+ 以下の表は、クエリ文字列のパラメータにアクセスする方法を比較しています。
+
+ Express でクエリパラメータにアクセスするには、
+ 完全な例については、4_parameters プロジェクトを参照してください。
+
+ Ktor では、
+ 完全な例については、4_parameters プロジェクトを参照してください。
+
+ 前のセクションでは、プレーンテキストの内容で応答する方法をすでに見てきました。
+ JSON、ファイル、およびリダイレクトのレスポンスを送信する方法を見ていきましょう。
+
+ Express で適切なコンテンツタイプで JSON レスポンスを送信するには、
+ 完全な例については、5_send_response プロジェクトを参照してください。
+
+ Ktor では、
+ データを JSON にシリアル化するには、
+ その後、
+ 完全な例については、5_send_response プロジェクトを参照してください。
+
+ Express でファイルを使用して応答するには、
+ 完全な例については、5_send_response プロジェクトを参照してください。
+
+ Ktor は、クライアントにファイルを送信するための
+ 完全な例については、5_send_response プロジェクトを参照してください。
+
+ Express アプリケーションは、ファイルで応答する際に
+
+ 完全な例については、5_send_response プロジェクトを参照してください。
+
+ Ktor では、ファイルを添付ファイルとして転送するために
+ 完全な例については、5_send_response プロジェクトを参照してください。
+
+ Express でリダイレクトレスポンスを生成するには、
+ 完全な例については、5_send_response プロジェクトを参照してください。
+
+ Ktor では、リダイレクトレスポンスを送信するために
+ 完全な例については、5_send_response プロジェクトを参照してください。
+
+ Express と Ktor はどちらも、ビューを処理するためのテンプレートエンジンの使用をサポートしています。
+
+
+ このテンプレートで応答するには、
+ 完全な例については、6_templates プロジェクトを参照してください。
+
+ Ktor は、FreeMarker、Velocity など、いくつかの
+ 完全な例については、6_templates プロジェクトを参照してください。
+
+ このセクションでは、さまざまな形式のリクエストボディを受信する方法について説明します。
+
+ 以下の
+ サーバー側でこのリクエストのボディをプレーンテキストとして受信する方法を見てみましょう。
+
+ Express で着信リクエストボディを解析するには、
+
+ 完全な例については、7_receive_request プロジェクトを参照してください。
+
+ Ktor では、
+ 完全な例については、7_receive_request プロジェクトを参照してください。
+
+ このセクションでは、JSON ボディを受信する方法を見ていきます。
+ 以下のサンプルは、ボディに JSON オブジェクトを含む
+ Express で JSON を受信するには、
+ 完全な例については、7_receive_request プロジェクトを参照してください。
+
+ Ktor では、
+ 受信したデータをオブジェクトにデシリアライズするには、データクラスを作成する必要があります。
+
+ 次に、このデータクラスをパラメータとして受け取る
+ 完全な例については、7_receive_request プロジェクトを参照してください。
+
+ 次に、
+ プレーンテキストや JSON と同様に、Express では
+ 完全な例については、7_receive_request プロジェクトを参照してください。
+
+ Ktor では、
+ 完全な例については、7_receive_request プロジェクトを参照してください。
+
+ 次のユースケースは、バイナリデータの処理です。
+ 以下のリクエストは、
+ Express でバイナリデータを処理するには、パーサーのタイプを
+ 完全な例については、7_receive_request プロジェクトを参照してください。
+
+ Ktor は、バイトシーケンスを非同期で読み書きするための
+ 完全な例については、7_receive request プロジェクトを参照してください。
+
+ 最後のセクションでは、
+ Express ではマルチパートデータを解析するために別のモジュールが必要です。
+ 以下の例では、
+ 完全な例については、7_receive_request プロジェクトを参照してください。
+
+ Ktor では、マルチパートリクエストの一部として送信されたファイルを受信する必要がある場合、
+ 完全な例については、7_receive_request プロジェクトを参照してください。
+
+ 最後に、サーバー機能を拡張するためのミドルウェアの作成方法について説明します。
+ 以下の例は、Express と Ktor を使用してリクエストログを実装する方法を示しています。
+
+ Express では、ミドルウェアは
+ 完全な例については、8_middleware プロジェクトを参照してください。
+
+ Ktor では、
+ 完全な例については、8_middleware プロジェクトを参照してください。
+
+ このガイドではまだカバーされていないユースケースが、セッション管理、認可、データベース統合など多数あります。
+ これらの機能のほとんどについて、Ktor はアプリケーションにインストールして必要に応じて構成できる専用のプラグインを提供しています。
+ Ktor での開発を続けるには、一連のステップバイステップのガイドとすぐに使えるサンプルを提供している
+ コード例:
+ autoreload-engine-main,
+ autoreload-embedded-server
+
+ 開発中にサーバーを
+ 開発モードを有効にする
+
+ (オプション)監視パスを構成する
+
+ 変更時の再コンパイルを有効にする
+
+ オートリロードを使用するには、まず開発モードを有効にする必要があります。
+ これは、
+
+
+ 開発モードが有効になると、Ktorは作業ディレクトリからの出力ファイルを自動的に監視します。
+ 必要に応じて、監視パスを指定することで、監視対象のフォルダーを絞り込むことができます。
+
+ 開発モードを有効にすると、Ktorは作業ディレクトリからの出力ファイルの監視を開始します。
+ 例えば、Gradleでビルドされた
+ 監視パスを使用すると、監視対象のフォルダーのセットを絞り込むことができます。
+ これを行うには、監視パスの一部を指定します。
+ 例えば、
+
+ 次のように複数の監視パスを指定することもできます。
+
+ 完全な例はこちらで確認できます: autoreload-engine-main
+
+
+ 完全な例については、以下を参照してください。
+
+ autoreload-embedded-server
+
+
+ オートリロードは出力ファイルの変更を検出するため、プロジェクトをリビルドする必要があります。
+ これは IntelliJ IDEA で手動で行うか、Gradle の
+ IntelliJ IDEA でプロジェクトを手動でリビルドするには、メインメニューから
+ Gradle を使用して自動的にプロジェクトをリビルドするには、ターミナルで
+ プロジェクトのリロード時にテストの実行をスキップするには、
+ Ktorでは、ホストアドレス、ポート、
+
+ このセクションでは、サーバーを効果的に設定する方法を示すために、
+ 以下のコードスニペットは、Nettyエンジンと
+
+
+ 以下の例は、
+ これらのオプションに加えて、他のエンジン固有のプロパティを設定することもできます。
+ Netty固有のオプションは、
+
+ NettyApplicationEngine.Configuration
+
+ クラスによって公開されています。
+
+ Jetty固有のオプションは、
+
+ JettyApplicationEngineBase.Configuration
+
+ クラスによって公開されています。
+
+
+ configureServer
+
+ ブロック内でJettyサーバーを設定できます。これにより、
+ Server
+ インスタンスにアクセスできます。
+
+ CIO固有のオプションは、
+
+ CIOApplicationEngine.Configuration
+
+ クラスによって公開されています。
+ エンジンとしてTomcatを使用する場合、
+
+ configureTomcat
+
+ プロパティを使用して設定できます。これにより、
+ Tomcat
+ インスタンスにアクセスできます。
+
+ 以下の例は、
+
+ ApplicationEngine.Configuration
+
+ クラスで表されるカスタム設定を使用して、複数のコネクタエンドポイントでサーバーを実行する方法を示しています。
+
+ 完全な例については、
+
+ embedded-server-multiple-connectors
+ を参照してください。
+
+ カスタム環境を使用して
+
+ HTTPSを提供
+ することもできます。
+
+ Ktorでは、コマンドライン引数を使用して
+ これを実現するには、
+
+ CommandLineConfig
+
+ クラスを使用してコマンドライン引数を設定オブジェクトにパースし、それを設定ブロック内で渡します。
+
+ この例では、
+ サーバーを実行するには、次のように引数を指定します。
+
+ コード例:
+
+ %example_name%
+
+
+ このチュートリアルでは、最初のKtorサーバープロジェクトを作成、オープン、および実行する方法を学びます。プロジェクトが起動して実行されたら、一連のタスクを完了してKtorに慣れることができます。
+
+ これは、Ktorを使用したサーバーアプリケーション構築を開始するための一連のチュートリアルの最初のステップです。各チュートリアルは独立して行うことができますが、以下の推奨される順序に従うことを強くお勧めします。
+
+ 新しいKtorプロジェクトを作成する最も速い方法の1つは、ウェブベースのKtorプロジェクトジェネレーターを使用することです。
+
+ あるいは、IntelliJ IDEA Ultimate専用のKtorプラグインまたはKtor CLIツールを使用してプロジェクトを生成することもできます。
+
+ Ktorプロジェクトジェネレーターで新しいプロジェクトを作成するには、以下の手順に従ってください。
+ Ktorプロジェクトジェネレーターにアクセスします。
+
+
+ 以下の設定が利用可能です:
+
+
+
+ このチュートリアルでは、これらの設定はデフォルト値のままで構いません。
+
+ その下には、プロジェクトに追加できる一連の このチュートリアルでは、現段階でプラグインを追加する必要はありません。
+ ダウンロードが自動的に開始されます。 新しいプロジェクトが生成されたので、続けてKtorプロジェクトの展開と実行に進んでください。
+ このセクションでは、IntelliJ IDEA Ultimate用のKtorプラグインを使用したプロジェクトのセットアップについて説明します。
+
+ 新しいKtorプロジェクトを作成するには、IntelliJ IDEAを開き、以下の手順に従ってください。
+
+ ウェルカム画面で、
+ または、メインメニューから
+
+ 右側のペインで、以下の設定を指定できます。
+
+
+
+
+
+
+
+
+ 以下の設定が利用可能です:
+
+
+
+ このチュートリアルでは、これらの設定はデフォルト値のままで構いません。
+
+ このページでは、一連の このチュートリアルでは、現段階でプラグインを追加する必要はありません。
+
+ 新しいプロジェクトを作成したので、続けてアプリケーションのオープン、探索、および実行方法を学習してください。
+
+ このセクションでは、Ktor CLIツールを使用したプロジェクトのセットアップについて説明します。
+
+ 新しいKtorプロジェクトを作成するには、お好みのターミナルを開き、以下の手順に従ってください。
+
+ (オプション)プロジェクト名の下の このチュートリアルでは、現段階でプラグインを追加する必要はありません。
+ あるいは、
+ このセクションでは、コマンドラインからプロジェクトを展開、ビルド、および実行する方法を学びます。以下の手順は、次のような状況を想定しています。
+ 必要に応じて、自身のセットアップに合わせて名前とパスを変更してください。 お好みのコマンドラインツールを開き、以下の手順に従います。 ターミナルウィンドウで、プロジェクトをダウンロードしたフォルダに移動します。 ZIPアーカイブを同名のフォルダに展開します。 ディレクトリには、ZIPアーカイブと展開されたフォルダが含まれるようになります。 ディレクトリから、新しく作成されたフォルダに移動します。 macOSおよびUNIXシステムでは、システムが実行可能なコマンドとして認識できるように、Gradleヘルパースクリプトを実行可能にする必要があります。これを行うには、 プロジェクトをビルドするには、次のコマンドを使用します。 ビルドが成功したら、次のステップに進んでプロジェクトを実行します。 プロジェクトを実行するには、次のコマンドを使用します。 プロジェクトが実行されていることを確認するには、ターミナル出力に表示されているURL(http://0.0.0.0:8080)をブラウザで開きます。
+ ブラウザに「Hello World!」というメッセージが表示されるはずです。 おめでとうございます!Ktorプロジェクトの起動に成功しました。 IntelliJ IDEAがインストールされている場合は、コマンドラインから簡単にプロジェクトを開くことができます。
+
+ プロジェクトフォルダ内にいることを確認し、
+ または、手動でプロジェクトを開くには、IntelliJ IDEAを起動します。
+
+ ウェルカム画面が開いた場合は、 プロジェクトを開くと、次のような構造が表示されます。
+ 完全なレイアウトを表示するには、各フォルダの横にある展開矢印をクリックして、
+ アプリケーションのソースコードは、 プロジェクト名は
+ 構成ファイルやその他の種類のコンテンツは、 IntelliJ IDEA内からプロジェクトを実行するには: 右側のサイドバーにあるGradleアイコン( このツールウィンドウ内で、 KtorアプリケーションがIDEの下部にある実行(Run)ツールウィンドウで起動します。 以前にコマンドラインに表示されていたものと同じメッセージが、 プロジェクトが実行されていることを確認するには、指定されたURL(http://0.0.0.0:8080)をブラウザで開きます。 画面に「Hello World!」というメッセージが再び表示されるはずです。
+
+ これらのオプションの詳細については、IntelliJ IDEA実行ツールウィンドウのドキュメントを参照してください。
+ 試してみることをお勧めする追加タスクをいくつか紹介します:
+ これらのタスクは互いに依存していませんが、徐々に難易度が上がっていきます。宣言された順序で試すことが、段階的に学習するための最も簡単な方法です。簡単にするため、また重複を避けるため、以下の説明はタスクを順番に試していることを前提としています。
+
+ コーディングが必要な箇所については、コードと対応するインポートの両方を指定しています。IDEがこれらのインポートを自動的に追加してくれる場合もあります。
+
+ 構成を外部のYAMLまたはHOCONファイルに保存することを選択した場合、 再実行ボタン( アプリケーションが新しいポート番号で実行されていることを確認するには、新しいURL(http://0.0.0.0:9292)をブラウザで開くか、IntelliJ IDEAで新しいHTTPリクエストファイルを作成します。
+ 新しいKtorプロジェクトを作成する際、構成をコード内に保存するか、外部のYAMLまたはHOCONファイルに保存するかを選択できます。
+
+ 構成をコード内に保存することを選択した場合、 再実行ボタン( アプリケーションが新しいポート番号で実行されていることを確認するには、新しいURL(http://0.0.0.0:9292)をブラウザで開くか、IntelliJ IDEAで新しいHTTPリクエストファイルを作成します。
+ 新しいエンドポイントを作成するには、次のように追加のルートを挿入します。 IDEは自動的に 再実行ボタン( ブラウザで新しいURL(http://0.0.0.0:9292/test1)をリクエストします。ポート番号は、デフォルトポートの変更タスクを完了したかどうかによって異なります。以下のような出力が表示されるはずです。 HTTPリクエストファイルを作成した場合は、そこでも新しいエンドポイントを確認できます。 この行の意味は次のとおりです: IDEが自動的に追加しない場合は、次のインポートを追加してください。 または、 新しいディレクトリに 新しく作成したフォルダを右クリックし、 新しいファイルに 新しく作成したファイルページに、有効なHTMLを入力します(例): 再実行ボタン( ブラウザでhttp://0.0.0.0:9292/content/sample.htmlを開くと、サンプルページの内容が表示されるはずです。
+ Ktorは これを利用するには、以下の手順に従ってください。
+ 次に、 最後に、組み込みの
+ IntelliJ IDEAでテストを実行する標準的な方法のいずれかでテストを実行できます。Ktorの新しいインスタンスを実行しているため、テストの成否はアプリケーションが
+ 新しいHTTPエンドポイントの追加に成功した場合は、この追加のテストを追加してください:
+ 以下の追加のインポートを追加します:
+
+ 次のステップでは、プラグインを手動で追加および構成する方法を学びます。これを達成するための4つのステップがあります:
+ これらの行は、 以下のインポートを追加します:
+ 通常、レスポンスにはHTTPエラーコードが設定されますが、このタスクの目的上、出力はブラウザに直接表示されます。
+ これで、URL 再実行ボタン( ブラウザで、URL http://0.0.0.0:9292/error-testにアクセスします。次のようにエラーメッセージが表示されるはずです:
+ 追加タスクの最後まで到達したなら、Ktorサーバーの構成、Ktorプラグインの統合、および新しいルートの実装について理解できたはずです。しかし、これはほんの始まりに過ぎません。Ktorの基礎的な概念をさらに深く掘り下げるには、このガイドの次のチュートリアルに進んでください。
+
+ 次は、
+ コード例:
+ embedded-server,
+ engine-main,
+ engine-main-yaml
+
+ Ktorアプリケーションを作成する前に、アプリケーションをどのように
+
+
+ この場合、ネットワークリクエストを処理するために使用されるアプリケーション
+
+ この場合、Ktorアプリケーションはサーブレットコンテナ(TomcatやJettyなど)内にデプロイできます。サーブレットコンテナがアプリケーションのライフサイクルと接続設定を制御します。
+
+ Ktorサーバーアプリケーションを自己完結型パッケージとして提供するには、まずサーバーを作成する必要があります。
+ サーバーの設定には、サーバー
+
+
+
+ 完全な例については、
+
+ embedded-server
+
+ を参照してください。
+
+
+ どのモジュールを読み込むかの指定に加えて、設定ファイルにはポート、ホスト、SSL設定などのさまざまなサーバーパラメータを含めることができます。例えば、以下の設定ではサーバーポートを
+ 完全な例については、
+
+ engine-main
+
+ および
+
+ engine-main-yaml
+
+ を参照してください。
+
+ Ktorアプリケーションは、TomcatやJettyを含むサーブレットコンテナ内で実行およびデプロイできます。
+ サーブレットコンテナ内にデプロイするには、
+
+ コード例:
+
+ %example_name%
+
+
+ 使用されているプラグイン:
+ このチュートリアルでは、KotlinとKtorを使用してバックエンドサービスを構築する方法を説明し、JSONデータを生成するRESTful APIの例を紹介します。
+
+
+ 以下の内容を学習します:
+ このチュートリアルは単独で行うこともできますが、 IntelliJ IDEAのインストールをお勧めしますが、お好みの他のIDEを使用することもできます。
+ このチュートリアルでは、既存のタスクマネージャーをRESTfulサービスとして書き直します。これを行うために、いくつかのKtor
+ 既存のプロジェクトに手動で追加することもできますが、新しいプロジェクトを生成してから、前のチュートリアルのコードを段階的に追加していく方が簡単です。進めながらすべてのコードを反復するため、前のプロジェクトを手元に用意しておく必要はありません。
+
+ Ktor Project Generatorにアクセスします。
+
+ プラグインセクションで、以下のプラグインを検索し、
+
+ IntelliJ IDEAでKtorプロジェクトを開き、探索し、実行するチュートリアルで説明したように、IntelliJ IDEAでプロジェクトを開きます。
+
+
+
+ 前のチュートリアルでは、拡張関数を使用して
+
+ 前のチュートリアルと同様に、URL IntelliJ IDEAで、実行ボタン(
+ ブラウザで http://0.0.0.0:8080/tasks にアクセスします。以下のように、タスクリストのJSON版が表示されるはずです:
+ 明らかに、私たちの代わりに多くの処理が行われています。具体的には何が起きているのでしょうか?
+ プロジェクトを作成した際、
+ HTTPでは、クライアントは
+ 以下の例を考えてみましょう:
+ Content Negotiationプラグインは、データをブラウザに送り返すためのフォーマットを見つける必要があります。プロジェクト内の生成されたコードを見ると、
+ このコードは
+ ブラウザからのリクエストの場合、
+ 本番環境では、通常JSONをブラウザに直接表示することはありません。代わりに、ブラウザで実行されているJavaScriptコードがリクエストを行い、返されたデータをシングルページアプリケーション(SPA)の一部として表示します。通常、この種のアプリケーションは React、Angular、または Vue.js のようなフレームワークを使用して記述されます。
+
+ これをシミュレートするために、
+ このページにはHTMLフォームと空のテーブルが含まれています。フォームを送信すると、JavaScriptイベントハンドラーが
+ IntelliJ IDEAで、再実行ボタン(
+ URL http://0.0.0.0:8080/static/index.html にアクセスします。
+ コンテンツネゴシエーションのプロセスに慣れたところで、
+ タスクのリポジトリは変更なしで再利用できるので、まずそれを行いましょう。
+
+
+
+ リポジトリを作成したので、GETリクエスト用のルートを実装できます。タスクをHTMLに変換することを心配する必要がなくなったため、以前のコードを簡略化できます:
+
+
+
+ これにより、サーバーは以下のGETリクエストに応答できるようになります:
+ IntelliJ IDEAで、再実行ボタン( ブラウザでこれらのルートをテストできます。例えば、http://0.0.0.0:8080/tasks/byPriority/Medium にアクセスすると、
+ この種のリクエストは通常JavaScriptから行われるため、より詳細なテストが好ましいです。このために、Postmanのような専門的なツールを使用できます。
+ Postmanで、URL
+ IntelliJ IDEA Ultimateでは、HTTPリクエストファイルで同じ手順を実行できます。
+ プロジェクトのルートディレクトリに、新しい
+
+ IntelliJ IDEA内でリクエストを送信するには、その横にあるガターアイコン( これにより、
+ 前のチュートリアルでは、タスクはHTMLフォームを通じて作成されました。しかし、現在はRESTfulサービスを構築しているため、その必要はありません。代わりに、主要な処理を肩代わりしてくれる
+
+ 以下のように、新しいPOSTルートを
+ 以下の新しいインポートを追加します:
+
+ POSTリクエストが
+ アプリケーションを再起動します。
+
+ Postmanでこの機能をテストするには、URL
+
+ http://0.0.0.0:8080/tasks にGETリクエストを送信することで、タスクが追加されたことを確認できます。
+
+ IntelliJ IDEA Ultimate内では、HTTPリクエストファイルに以下を追加することで同じ手順を実行できます:
+
+ サービスの基本操作の追加はほぼ完了しました。これらはCRUD(Create, Read, Update, and Delete)操作としてよくまとめられます。ここでは削除操作を実装します。
+
+
+
+ アプリケーションを再起動します。
+
+ HTTPリクエストファイルに以下のDELETEリクエストを追加します:
+
+ IntelliJ IDEA内でDELETEリクエストを送信するには、その横にあるガターアイコン(
+ これまでは手動でアプリケーションをテストしてきましたが、すでにお気づきの通り、このアプローチは時間がかかり、規模の拡大に対応できません。代わりに、組み込みの
+
+
+ サーバーで行ったのと同様に、プラグインに
+
+ Ktor Clientや同様のライブラリを使用してサービスをテストするのは便利ですが、品質保証(QA)の観点からは欠点があります。サーバーがJSONを直接処理しない場合、JSONの構造に関する想定が正しいかどうか確信が持てないためです。
+
+ 例えば、以下のような想定です:
+
+ サービスが複数のクライアントによって使用されることを目的としている場合、JSON構造に自信を持つことが不可欠です。これを実現するには、Ktor Clientを使用してサーバーからテキストを取得し、JSONPath ライブラリを使用してこのコンテンツを分析します。
+
+
+ JsonPath クエリは以下のように機能します:
+
+ このようなクエリを使用して、返されたJSONに対する理解を確認できます。コードのリファクタリングやサービスの再デプロイを行う際、現在のフレームワークでのデシリアライズを妨げない変更であっても、シリアライズにおけるあらゆる修正が特定されます。これにより、自信を持って公開APIを再公開できます。
+
+ おめでとうございます!タスクマネージャーアプリケーションのRESTful APIサービスの作成を完了し、Ktor ClientとJsonPathを使用したユニットテストの要点を学びました。
+
+ コード例:
+
+ %example_name%
+
+
+ 使用されるプラグイン:
+ このチュートリアルでは、Kotlin と Ktor、そして Thymeleaf テンプレートを使用して、インタラクティブな Web サイトを構築する方法を学びます。
+
+
+ 次のような理由から、すべての実装をサーバー側に保持し、クライアントにはマークアップのみを送信したい場合があります。
+
+ Ktor は、
+ このチュートリアルは単独で行うことができますが、RESTful API の作成方法を学ぶために、 IntelliJ IDEA をインストールすることをお勧めしますが、お好みの他の IDE を使用することもできます。
+
+ このチュートリアルでは、
+ 既存のプロジェクトにこれらのプラグインを手動で追加することもできますが、新しいプロジェクトを生成して、前のチュートリアルのコードを徐々に組み込んでいく方が簡単です。必要なコードはすべて途中で提供されるため、前のプロジェクトが手元になくても大丈夫です。
+
+ Ktor Project Generator
+ に移動します。
+
+ 次の画面で、
+
+
+
+
+ ここでも、
+ 次のことを覚えているかもしれません。
+
+ 今回の目標は、タスクの内容をブラウザに書き込むサーバーページを作成することです。
+
+
+ サーバーが 次の
+ Thymeleaf プラグインの初期化内で、Ktor は
+
+ この場合、 IntelliJ IDEA で、実行ボタン
+ (
+ ブラウザで http://0.0.0.0:8080/tasks に移動します。以下に示すように、現在のすべてのタスクがテーブルに表示されるはずです。
+
+ すべてのサーバーページフレームワークと同様に、Thymeleaf テンプレートは静的コンテンツ(ブラウザに送信されるもの)と動的コンテンツ(サーバーで実行されるもの)を混合します。もし Freemarker などの別のフレームワークを選択していた場合、少し異なる構文で同じ機能を提供できたでしょう。
+ サーバーページをリクエストするプロセスに慣れたので、前のチュートリアルの機能をこのチュートリアルに移行し続けましょう。
+
+ これは、例えば
+ このファイルはすでに生成されたプロジェクトの一部であるため、追加したい機能のホームページとして使用できます。
+
+
+ IntelliJ IDEA で、再実行ボタン (
+ ブラウザで http://localhost:8080/static/index.html に移動します。タスクの表示、フィルタリング、作成を行うためのリンクボタンと 3 つの HTML フォームが表示されるはずです。
+
+ タスクを
+ 例えば、
+ タスクのリポジトリは、前のチュートリアルのものと同一のままで構いません。
+
+
+ リポジトリを作成したので、GET リクエストのルートを実装できます。
+
+ 現在のバージョンの
+ 上記のコードは次のように要約できます。
+ これらすべてを機能させるには、追加のテンプレートを追加する必要があります。
+ 同じフォルダに、
+
+ 次に、
+
+ IntelliJ IDEA で、再実行ボタン (
+
+ おめでとうございます!タスクマネージャーを Web アプリケーションとして再構築し、Thymeleaf テンプレートの使用方法を学びました。
+
+ コード例:
+
+ %example_name%
+
+
+ 使用するプラグイン:
+ この記事では、KotlinとKtorを使用してWebSocketアプリケーションを作成するプロセスを説明します。これは、 この記事では、以下の方法について説明します: このチュートリアルは単独で行うこともできますが、 IntelliJ IDEAのインストールを推奨しますが、お好みの他のIDEを使用することも可能です。
+
+ このチュートリアルでは、
+ Ktor Project Generatorにアクセスします。
+
+ プラグインセクションで、以下のプラグインを検索し、
+
+ プラグインを追加すると、プラグインセクションの右上に表示されます。
+ プロジェクトに追加されるすべてのプラグインのリストが表示されます:
+
+ ダウンロードが完了したら、IntelliJ IDEAでプロジェクトを開き、以下の手順に従います:
+
+
+
+ WebSocketsプラグインを含めたため、ジェネレーターによって
+
+ デモンストレーション目的で、タスクの送信間に1秒の遅延が導入されています。これにより、クライアントでタスクが段階的に表示される様子を観察できます。この遅延がない場合、この例は以前の記事で開発した
+ このイテレーションの最後のステップは、このエンドポイント用のクライアントを作成することです。
+
+ このページでは、すべての最新ブラウザで使用可能な IntelliJ IDEAで実行ボタン
+ (
+ http://0.0.0.0:8080/static/index.htmlにアクセスします。ボタンのあるフォームと空のテーブルが表示されるはずです:
+
+ フォームをクリックすると、サーバーからタスクが読み込まれ、1秒間に1つのペースで表示されます。その結果、テーブルには段階的にデータが入力されます。ブラウザの
+ これで、サービスは期待どおりに動作しています。WebSocket接続が開かれ、アイテムがクライアントに送信され、接続が閉じられます。基礎となるネットワークには多くの複雑さがありますが、Ktorはデフォルトでこれらすべてを処理します。
+
+ 次のイテレーションに進む前に、WebSocketの基本をいくつか確認しておくと役立つかもしれません。WebSocketにすでに精通している場合は、サービスの設計改善に進んでかまいません。
+
+ これまでのチュートリアルでは、クライアントはHTTPリクエストを送信し、HTTPレスポンスを受信していました。これはうまく機能し、インターネットのスケーラビリティと耐障害性を可能にしています。
+ しかし、以下のようなシナリオには適していません:
+ これらのシナリオの例としては、株取引、映画やコンサートのチケット購入、オンラインオークションでの入札、ソーシャルメディアのチャット機能などがあります。WebSocketは、これらの状況に対処するために開発されました。
+
+ WebSocket接続はTCP上で確立され、長期間持続させることができます。接続は
+ WebSocket APIは、4つのイベント(open、message、close、error)と2つのアクション(send、close)を定義しています。この機能へのアクセス方法は、言語やライブラリによって異なります。例えば、Kotlinでは、着信メッセージのシーケンスを 次に、より高度な例に対応できるように既存のコードをリファクタリングします。
+
+ このコードは、以前のチュートリアルで見た覚えがあるかもしれません。
+
+ WebSocketのパワーを説明するために、次のような新しいエンドポイントを作成します:
+
+ このコードで以下のことを行いました:
+ この機能をテストするために、
+
+
+ この新しいページには、ユーザーが新しいタスクの情報を入力できるHTMLフォームが導入されています。フォームを送信すると、
+ IntelliJ IDEAで、再実行ボタン ( この機能をテストするには、2つのブラウザを並べて開き、以下の手順に従います。
+ QAプロセスを効率化し、高速、再現可能、かつハンズフリーにするために、Ktorに組み込まれている
+ Ktor Client内で
+ IntelliJ IDEAで、エディターの右側にあるGradle通知アイコン
+ (ctor (constructor: コンストラクタ) に由来しており、最初の文字をKotlinの「K」に置き換えたものです。
+ Runtime.getRuntime().addShutdownHook を使用できます。
+ call.request.origin プロパティから元の呼び出し元(プロキシ)に関する 接続情報 を取得できます。
+ jetbrains.space からKtorのナイトリービルドを取得できます。
+ 詳細は Early Access Program をご確認ください。
+ Server レスポンスヘッダーを送信できます。
+ call.respond* 関数を呼び出しているにもかかわらず、再度それを呼び出そうとしていることを意味します。
+ resources フォルダに設定ファイルが存在し、その resources フォルダがリソースフォルダとして正しくマークされていることを確認してください。
+ ベースとなる動作プロジェクトを作成するために、Ktorプロジェクトジェネレーター や IntelliJ IDEA Ultimate用のKtorプラグイン の使用を検討してください。詳細については、CURL -I は HEAD リクエストを実行する CURL --head のエイリアスです。
+ デフォルトでは、Ktorは GET ハンドラーに対する HEAD リクエストを処理しません。
+ この機能を有効にするには、HttpsRedirect プラグインがそれを通常のHTTPリクエストであると判断し、リダイレクトを返してしまいます。
+ curl ライブラリのインストールが必要です。
+ Windowsでは、MinGW/MSYS2の curl バイナリの利用を検討してください。
+ libcurl をインストールします。
+ PATH に Accept ヘッダーが目的のコンテンツタイプを指定していること、およびサーバーのレスポンスの Content-Type ヘッダーがクライアント側の期待する型と一致していることを確認してください。
+
+
+
+
+
+
+
+ ktor-client-core は、メインのクライアント機能を提供するコア依存関係です。ktor-client-cio は、ネットワークリクエストを処理する
+ HttpClient.get() メソッドを使用して HttpResponse クラスのオブジェクトとして受け取ります。
+ get() 関数に対して次のエラーを表示します。
+
+ main() 関数を suspend にする必要があります。
+ suspend 関数の呼び出しについての詳細は、コルーチンの基本を参照してください。
+
+ println() 関数を使用してサーバーから返された ステータスコード を出力し、close() 関数を使用してストリームを閉じ、関連するリソースを解放します。
+ main() 関数の横にあるガターアイコンをクリックし、
+
+ 200 OK メッセージを返しますが、SLF4J が StaticLoggerBinder クラスを見つけられず、デフォルトで NOP(何もしない)ロガー実装が使用されることを示すエラーメッセージも表示されます。これは事実上、ロギングが無効であることを意味します。
+ ) をクリックしてアプリケーションを再起動します。
+
200 OK メッセージが表示されるはずです。
+
+ ) をクリックしてアプリケーションを再起動します。
+
+ SSE は SSE プラグインをインストールするには、クライアント設定ブロック内の install 関数に渡します。
+ install ブロック内で SSE プラグインを設定できます。
+ maxReconnectionAttempts を 0 より大きい値に設定します。また、reconnectionTime を使用して試行間の遅延を設定することもできます。
+ reconnectionTime だけ待機します。接続を再確立するために、指定された maxReconnectionAttempts まで試行を繰り返します。
+ retry フィールドのみを含むイベントを含めるように設定しています。
+ SSEBufferPolicy 型は、処理された SSE データを保存するためのいくつかの戦略を提供します。
+ これらのポリシーは、ストリームのどの程度をメモリに保持し、エラー発生時に利用可能にするかを制御します。
+ Off (デフォルト)LastLines(n)LastEventLastEvents(n)Allresponse?.bodyAsText() を使用してバッファにアクセスできます。
+ ClientSSESession
+
+ インターフェースによって表されます。このインターフェースは、サーバーからサーバー送信イベントを受信できるようにする API を公開しています。
+ HttpClient を使用すると、次のいずれかの方法で SSE セッションにアクセスできます。
+
+ sse()
+
+ 関数は、SSE セッションを作成し、それに対してアクションを実行できるようにします。
+ sseSession()
+
+ 関数を使用すると、SSE セッションを開くことができます。
+
+
+ urlString パラメータを使用して、URL 全体を文字列として指定します。schema、host、port、path パラメータを使用して、それぞれプロトコルスキーム、ドメイン名、ポート番号、パス名を指定します。
+ ClientSSESession および ClientSSESessionWithDeserialization のインスタンスは、セッションの期間中のみ有効です。serverSentEvents { ... } ブロックが完了するか、接続が閉じられると、それらのスコープは自動的にキャンセルされます。
+ reconnectionTimeshowCommentEventsshowRetryEventsretry フィールドのみを含むイベントを表示するかどうかを指定します。
+ deserializeTypedServerSentEvent の data フィールドをオブジェクトに変換するためのデシリアライザー関数。詳細については、デシリアライズを参照してください。
+ ClientSSESession
+ コンテキストにアクセスできます。ブロック内では以下のプロパティが利用可能です。
+ callHttpClientCall。
+ incomingevents エンドポイントを使用して新しい SSE セッションを作成し、incoming プロパティを通じてイベントを読み取り、受信した
+ ServerSentEvent
+ を出力します。
+ deserialize パラメータを使用してカスタムデシリアライズ関数を提供し、
+
+ ClientSSESessionWithDeserialization
+
+ クラスを使用してデシリアライズされたイベントを処理します。
+ kotlinx.serialization を使用して JSON データをデシリアライズする例です。
+ io.ktor:ktor-client-websockets
+ WebSocketsを使用するには、ビルドスクリプトに %artifact_name% アーティファクトを含める必要があります。WebSocketsプラグインをインストールするには、クライアント設定ブロック内の install 関数に渡します。install ブロック内でプラグインを設定できます。
+ maxFrameSizeFrame の最大サイズを設定します。
+ contentConverterpingIntervalMillisLong 形式で指定します。
+ pingIntervalDuration 形式で指定します。
+ pingInterval および pingIntervalMillis プロパティは、OkHttpエンジンには適用されません。OkHttpのping間隔を設定するには、エンジン設定を使用できます。
+ 20_000ミリ秒)のping間隔で設定し、pingフレームを自動的に送信してWebSocket接続を維持するようにしています。
+ HttpClient は、WebSocketセッションにアクセスするための2つの主要な方法を提供します。
+
+
+ DefaultClientWebSocketSession を受け取ります。DefaultClientWebSocketSession インスタンスを返し、runBlocking や launch スコープの外でセッションにアクセスすることを可能にします。
+ send()send() 関数を使用します。
+ outgoingoutgoing プロパティを使用します。フレームは Frame クラスによって表されます。
+ incomingincoming プロパティを使用します。フレームは Frame クラスによって表されます。
+ close()close() 関数を使用します。
+
+
+ Frame.Text はテキストフレームを表します。内容を読み取るには Frame.Text.readText() を使用します。
+ Frame.Binary はバイナリフレームを表します。内容を読み取るには Frame.Binary.readBytes() を使用します。
+ Frame.Close はクローズフレームを表します。セッション終了の理由を取得するには Frame.Close.readReason() を使用します。
+ echo WebSocketエンドポイントを作成し、サーバーとの間でメッセージを送受信する方法を示します。ktorグループの外側にstorageグループを追加します。
+ configureDatabases()関数を更新します。
+ configureDatabases()関数はApplicationConfigを受け取るようになり、config.propertyを使用してカスタム設定をロードします。
+ environment.configをconfigureDatabases()に渡します。
+
+
+
+
+
+
+ webサービスは、イメージ内にパッケージ化されたKtorアプリケーションを実行するために使用されます。
+ dbサービスは、postgresイメージを使用して、タスクを保存するためのktor_tutorial_dbデータベースを作成します。
+ docker compose upコマンドを使用して、イメージをビルドしコンテナを起動します。
+
+
+
+
+
+
+
+ )
+ をクリックして構成を実行します。
+
+
+ sayHello()関数の呼び出しがあることがわかります:
+ sayHello()関数は
+ sayHello() 関数が使用されていることがわかります:
+
+
+Greeting 型では、期待宣言と実効宣言 (expected and actual declarations) を通じて、プラットフォーム固有の API を使用して現在のプラットフォームの名前を取得します。
+ getPlatform() 関数が expect キーワードとともに宣言されています:
+ getPlatform() 関数の actual 宣言を提供します:
+
+ )
+ をクリックして構成を実行します。
+
+ Greeting 型を利用しているということです。そして、この型は共通の Platform インターフェースを実装するプラットフォーム固有のクラスを使用しています。
+ kotlinx.serialization 依存関係を定義します:
+ Task
+ クラスは、kotlinx.serialization
+ ライブラリの Serializable 型でアノテーションされています:
+ Application.module() 関数内に配置している点が異なります。
+ ContentNegotiation 型と json() 関数のインポートが正しく機能するはずです。
+
+
+ TaskApi 型をクライアントに追加できます。
+ 1.2.3.4 を現在のマシンのIPアドレスに置き換えてください。Android仮想デバイスやiOSシミュレーター上で動作するコードからは、0.0.0.0 や localhost への呼び出しを行うことはできません。
+ localhost にアクセスできないため、マシンの実際のIPアドレスが必要です。IPアドレスを確認するには、以下のいずれかのコマンドを実行してください:
+
+
+ ifconfig | grep "inet " | grep -v 127.0.0.1hostname -I | awk '{print $1}'ipconfig を実行し、「IPv4 アドレス」を探しますTaskApi 型を使用してサーバーからタスクのリストを取得し、各タスクの名前を列(カラム)に表示します:
+
+
+ title を変更し、state プロパティを設定してコードを修正します:
+
+
+
+
+ App を以下の App および TaskCard コンポーザブルに置き換えます:
+ LaunchedEffect 型を使用することで起動時にすべてのタスクが読み込まれ、LazyColumn コンポーザブルによってユーザーはタスクをスクロールできるようになります。
+ TaskCard コンポーザブルが作成され、これには各 Task の詳細を表示するための Card が使用されています。タスクを削除および更新するためのボタンも追加されました。
+
+ UpdateTaskDialog コンポーザブルと必要なインポートを追加します:
+ Task の詳細を表示するコンポーザブルです。description(説明)と priority(優先度)は、更新できるように TextField コンポーザブル内に配置されています。ユーザーが更新ボタンを押すと、onConfirm() コールバックが実行されます。
+ App コンポーザブルを更新します:
+ UpdateTaskDialog コンポーザブルを呼び出します。その際、onConfirm() コールバックには TaskApi を使用してサーバーに POST リクエストを送信するように設定されています。
+ TaskCard コンポーザブルを作成する際に、onUpdate() コールバックを使用して currentTask 状態変数を設定します。
+
+
+
+
+
+
+
+
+
+express-generator ツールを使用して、新しい Express アプリケーションを生成できます。
+
+
+
+
+
+
+
+
+ktor new コマンドを使用して Ktor プロジェクトを生成します。
+ GET リクエストを受け取り、定義済みのプレーンテキストで応答する、最もシンプルなサーバーアプリケーションを作成する方法を見ていきます。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+staticFiles() 関数を使用して、
+
+ GET、POST など) とパスで定義された特定のエンドポイントに対して行われた着信リクエストを処理できます。
+ 以下の例は、GET および POST リクエストを処理する方法を示しています。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+POST、PUT、または PATCH リクエストのリクエストボディを受信する方法については、リクエストの受信を参照してください。
+
+
+
+
+
+
+
+
+app.route() を使用して、ルートパスに対してチェーン可能なルートハンドラーを作成できます。
+
+
+
+
+
+
+route 関数を提供しており、これによってパスを定義し、そのパスの HTTP メソッドをネストされた関数として配置します。
+
+
+
+
+
+
+
+
+express.Router クラスを提供しています。
+ アプリケーションのディレクトリに
+
+
+
+
+
+Routing 型の拡張関数を使用して実際のルートを定義するのが一般的なパターンです。
+ 以下のサンプル (birdsRoutes 拡張関数を定義しています。
+ アプリケーション (routing ブロック内でこの関数を呼び出すことで、対応するルートを含めることができます。
+
+
+
+
+
+
+
+
+Request.params を使用できます。
+ たとえば、以下のコードスニペットの req.params["login"] は、
+
+
+
+
+
+{param} 構文を使用して定義されます。
+ ルートハンドラーでルートパラメータにアクセスするには、call.parameters を使用できます。
+
+
+
+
+
+
+
+
+Request.query を使用できます。
+ たとえば、以下のコードスニペットの req.query['price'] は、
+
+
+
+
+
+call.request.queryParameters を使用してクエリパラメータにアクセスできます。
+
+
+
+
+
+
+
+
+res.json 関数を呼び出します。
+
+
+
+
+
+
+@Serializable アノテーションを付けたデータクラスを作成する必要があります。
+ call.respond を使用して、レスポンスでこのクラスのオブジェクトを送信できます。
+
+
+
+
+
+
+
+
+res.sendFile を使用します。
+
+
+
+
+
+
+call.respondFile 関数を提供しています。
+
+
+
+
+
+
+
+
+res.download 関数は、指定されたファイルを添付ファイルとして転送します。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+redirect 関数を呼び出します。
+
+
+
+
+
+
+respondRedirect を使用します。
+
+
+
+
+
+
+
+
+res.render を呼び出します。
+
+
+
+
+
+
+FreeMarker プラグインをインストールして構成し、call.respond を使用してテンプレートを送信します。
+ POST リクエストは、テキストデータをサーバーに送信します。
+
+
+
+
+
+
+
+
+body-parser を追加する必要があります。
+ post ハンドラーでは、テキストパーサー (bodyParser.text) を渡す必要があります。
+ リクエストボディは req.body プロパティから利用できます。
+
+
+
+
+
+
+call.receiveText を使用してボディをテキストとして受信できます。
+ POST リクエストを示しています。
+
+
+
+
+
+
+
+
+bodyParser.json を使用します。
+
+
+
+
+
+
+Json シリアライザーを構成する必要があります。
+ receive メソッドを使用します。
+ POST リクエストのサンプルを示しています。
+
+
+
+
+
+
+
+
+body-parser が必要です。
+ パーサーのタイプを bodyParser.urlencoded に設定する必要があります。
+
+
+
+
+
+
+call.receiveParameters 関数を使用します。
+
+
+
+
+
+
+
+
+raw に設定します。
+
+
+
+
+
+
+ByteReadChannel および ByteWriteChannel を提供しています。
+ POST リクエストは、
+
+
+
+
+
+
+
+
+
+
+
+
+
+receiveMultipart 関数を呼び出し、必要に応じて各パートをループします。
+ 以下の例では、PartData.FileItem を使用してファイルをバイトストリームとして受信しています。
+
+
+
+
+
+
+
+
+app.use を使用してアプリケーションにバインドされた関数です。
+
+
+
+
+
+
+onCall を処理する方法を示しています。
+
+
+
+
+
+
+モジュールの種類
+<= 3.2
+> 3.2
+
+
+ラムダ初期化子 (Lambda initializer)
+❌ サポートされていません
+❌ サポートされていません
+
+
+ブロッキング関数の参照
+✅ サポートされています
+❌ サポートされていません
+
+
+サスペンド関数の参照
+❌ サポートされていません
+✅ サポートされています
+
+
+設定の参照 (Config reference)
+✅ サポートされています
+✅ サポートされています
+
+
+ EngineMainを使用してサーバーを実行する場合は、設定ファイルで開発モードを有効にします。
+ embeddedServerを使用してサーバーを実行する場合は、
+ io.ktor.development
+ システムプロパティを使用できます。
+ classes を渡します。
+ サーバーの実行方法に応じて、以下の方法で監視パスを指定できます。
+
+
+watch オプションを指定します。
+ embeddedServer を使用している場合は、watchPaths パラメーターとして監視パスを渡します。
+ -t コマンドラインオプションを使用して継続的ビルド実行を有効にすることで行えます。
+
+
+-t オプションを付けて build タスクを実行します。
+ build タスクに -x オプションを渡すことができます。
+ embeddedServerを使用する場合、必要なパラメータを関数に直接渡すことでサーバーを設定します。
+
+ embeddedServer
+
+ 関数は、embeddedServerを実行するいくつかの異なる例を見ていきます。
+8080ポートを使用した基本的なサーバーセットアップを示しています。
+ portパラメータを0に設定すると、サーバーをランダムなポートで実行できることに注意してください。
+ embeddedServer関数はエンジンインスタンスを返すため、
+
+ ApplicationEngine.resolvedConnectors
+
+ 関数を使用してコード内でポート値を取得できます。
+ embeddedServer関数では、configureパラメータを使用してエンジン固有のオプションを渡すことができます。このパラメータには、すべてのエンジンに共通で、
+
+ ApplicationEngine.Configuration
+
+ クラスによって公開されているオプションが含まれます。
+ Nettyエンジンを使用してサーバーを設定する方法を示しています。
+ configureブロック内で、connectorを定義してホストとポートを指定し、さまざまなサーバーパラメータをカスタマイズしています。
+ connectors.add()メソッドは、指定されたホスト(127.0.0.1)とポート(8080)でコネクタを定義します。
+ idleTimeoutプロパティを使用して、接続が閉じられるまでにアイドル状態を維持できる期間を指定します。
+ embeddedServerを動的に設定できます。これは、ポート、ホスト、タイムアウトなどの設定を実行時に指定する必要がある場合に特に便利です。
+ Application.Configurationの
+
+ takeFrom()
+
+ 関数を使用して、portやhostなどのエンジン設定値を上書きしています。
+
+ loadCommonConfiguration()
+
+ 関数は、タイムアウトなどのルート環境からの設定をロードします。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ chmodコマンドを使用します。
+ ideaコマンドに続けて、現在のフォルダを表すピリオドを入力します。
+
+
+
+ )をクリックして、Gradleツールウィンドウを開きます。
+
+
+
+
+ )をクリックします。
+
)をクリックします。
+
+
+ portの値を、9292など、任意の見慣れない番号に変更します。
+ )をクリックして、アプリケーションを再起動します。
+ embeddedServer()関数内で、portパラメータを9292など、任意の別の番号に変更します。)をクリックして、アプリケーションを再起動します。
+ /test1というURLは、好きなものに変更できることに注意してください。ContentTypeのインポートを追加します。)をクリックして、アプリケーションを再起動します。
+ ###)を含む行が必要であることに注意してください。
+
+ staticResources()を呼び出すことで、アプリケーションがHTMLやJavaScriptファイルなどの標準的なウェブサイトコンテンツを提供できるようになります。このコンテンツはブラウザ内で実行できますが、サーバーの観点からは静的であると見なされます。
+ /contentは、このコンテンツを取得するために使用されるパスを指定します。
+ mycontentは、静的コンテンツを配置するフォルダの名前です。Ktorは、このフォルダをresourcesディレクトリ内で探します。
+ mycontentという名前を付け、)をクリックして、アプリケーションを再起動します。
+ testApplication()関数は、Ktorの新しいインスタンスを作成します。このインスタンスは、Nettyなどのサーバーではなく、テスト環境内で実行されます。configure()関数を使用して、embeddedServer()から呼び出されるのと同じセットアップを呼び出すことができます。clientオブジェクトとJUnitアサーションを使用して、サンプルリクエストを送信し、レスポンスを確認できます。0.0.0.0で実行されているかどうかには依存しないことに注意してください。
+
+
+ .configureRouting()メソッドに移動し、次のコード行を追加します:StatusPagesプラグインをインストールし、IllegalStateException型の例外がスローされたときにどのようなアクションを実行するかを指定します。.configureRouting()メソッド内にとどまり、次のように追加のルートを追加します:/error-testを持つエンドポイントが追加されました。このエンドポイントがトリガーされると、ハンドラーで使用されている型の例外がスローされます。)をクリックして、アプリケーションを再起動します。
+
+
+
+
+ embeddedServer関数は、
+
+ コード内でサーバーパラメータを設定
+
+ し、アプリケーションを素早く実行するためのシンプルな方法です。
+ EngineMainは、サーバーを設定するためのより高い柔軟性を提供します。
+
+ ファイル内でサーバーパラメータを指定
+
+ できるため、アプリケーションを再コンパイルせずに設定を変更できます。さらに、コマンドラインからアプリケーションを実行し、対応するコマンドライン引数を渡すことで必要なサーバーパラメータを上書きすることも可能です。
+ embeddedServer関数は、
+ Nettyエンジンを使用してサーバーを実行し、8080ポートでリスンします。
+ EngineMainは、選択したエンジンでサーバーを起動し、外部の8080に設定しています。
+ EngineMain.main()でサーバーを即座に起動する代わりに、EngineMain.createServer()を使用して手動でサーバーインスタンスを作成することもできます。詳細については、を参照してください。
+
+
+
+
+
+
+ プラグインを追加すると、プロジェクト設定の下にすべてのプラグインがリストされます。
+
+ enumとタスクを表すclassを追加します:
+ TaskをHTMLに変換しました。今回は、Taskクラスにkotlinx.serializationライブラリのSerializable型のアノテーションを付けています。
+ /tasks へのGETリクエストのルートを作成しました。今回は、タスクのリストを手動で変換する代わりに、リストをそのまま返しています。
+ )をクリックしてアプリケーションを起動します。
+ Accept ヘッダーを通じてレンダリング可能なコンテンツタイプを通知します。このヘッダーの値は1つ以上のコンテンツタイプです。上記の場合、ブラウザに組み込まれている開発ツールを使用して、このヘッダーの値を確認できます。
+ */* が含まれていることに注目してください。このヘッダーは、HTML、XML、または画像を受け入れることを示していますが、他のあらゆるコンテンツタイプも受け入れることを意味します。ContentNegotiation プラグインをインストールし、kotlinx.serialization プラグインも構成します。これにより、クライアントがリクエストを送信すると、サーバーはJSONとしてシリアライズされたオブジェクトを返送できます。
+ ContentNegotiation プラグインはJSONしか返せないことを認識しており、ブラウザは送られてきたものを何でも表示しようとします。そのため、リクエストは成功します。
+ Accept ヘッダーを application/json に設定して /tasks エンドポイントにリクエストを送信します。返されたデータはデシリアライズされ、HTMLテーブルに追加されます。
+ )をクリックしてアプリケーションを再起動します。
+
+ Application.configureRouting() 関数内の /tasks ルートのコードを、以下の実装に更新します:
+
+
+ /tasks はリポジトリ内のすべてのタスクを返します。/tasks/byName/{taskName} は指定された taskName でフィルタリングされたタスクを返します。
+ /tasks/byPriority/{priority} は指定された priority でフィルタリングされたタスクを返します。
+ )をクリックしてアプリケーションを再起動します。
+
Medium 優先度のすべてのタスクがJSON形式で表示されます:
+ http://0.0.0.0:8080/tasks/byPriority/Medium を使用して新しいGETリクエストを作成します。application/json に設定します。
+
+ )をクリックします。
+
+ kotlinx.serialization フレームワークを活用します。
+ Application.configureRouting() 関数に追加します:
+ /tasks に送信されると、kotlinx.serialization フレームワークがリクエストのボディを Task オブジェクトに変換します。これが成功すると、タスクがリポジトリに追加されます。デシリアライズプロセスが失敗した場合、サーバーは SerializationException を処理し、タスクが重複している場合は IllegalStateException を処理します。
+ http://0.0.0.0:8080/tasks に対して新しいPOSTリクエストを作成します。
+
+ TaskRepository オブジェクト内に、名前を基にタスクを削除する以下のメソッドを追加します:
+ routing() 関数に追加します:
+ )をクリックします。
+
+ client オブジェクトを使用してJSONの取得とデシリアライズを行う ContentNegotiation と kotlinx.serialization プラグインをインストールする必要があることに注意してください。
+
+
+ object が使用されているのに、値が array に格納されている。strings なのに、numbers として格納されている。dependencies ブロックに JSONPath ライブラリを追加します:
+
+
+ $[*].name は「ドキュメントを配列として扱い、各エントリの name プロパティの値を返す」ことを意味します。
+ $[?(@.priority == '$priority')].name は「指定された値と等しい優先度を持つ配列内のすべてのエントリの name プロパティの値を返す」ことを意味します。
+
+
+
+
+
+
+ プラグインを追加すると、プロジェクト設定の下に 3 つのプラグインがすべて表示されます。
+
+ enum と、タスクを表す data class を追加します。
+ Task オブジェクトを作成し、表示可能な形式でクライアントに送信したいと考えています。
+
+
+ kotlinx.serialization ライブラリの Serializable 型で Task クラスにアノテーションを付けました。
+ .configureRouting() 関数に、以下に示すように /tasks のルートを追加します。
+ /tasks へのリクエストを受け取ると、タスクのリストを作成し、それを Thymeleaf テンプレートに渡します。ThymeleafContent 型は、トリガーされるテンプレートの名前と、ページ上でアクセス可能な値のテーブルを受け取ります。
+ .configureThymeleaf 関数が表示されるはずです。all-tasks という名前はパス
+ src/main/resources/templates/thymeleaf/all-tasks.html
+ にマッピングされます。
+ )
+ をクリックしてアプリケーションを開始します。
+ /static/index.html へのリクエストが、次のパスからのコンテンツを提供することを意味します。
+ src/main/resources/static/index.html
+ ) をクリックしてアプリケーションを再起動します。
+
+ name または priority でフィルタリングする場合、GET リクエストを通じて HTML フォームを送信していることに注意してください。これは、パラメータが URL の後のクエリ文字列に追加されることを意味します。
+ Medium 優先度のタスクを検索する場合、サーバーに送信されるリクエストは次のようになります。
+ http://localhost:8080/tasks/byPriority?priority=Medium
+ .configureRouting() を以下の実装に置き換えます。
+
+
+ /tasks への GET リクエストでは、サーバーはリポジトリからすべてのタスクを取得し、
+ /tasks/byName への GET リクエストでは、サーバーは queryString からパラメータ name を取得し、一致するタスクを見つけ、
+ /tasks/byPriority への GET リクエストでは、サーバーは queryString からパラメータ priority を取得し、一致するタスクを見つけ、
+ /tasks への POST リクエストハンドラーを追加して、以下を実行します。
+
+
+ .configureRouting() メソッド内に次の post リクエストルートを追加します。
+ ) をクリックしてアプリケーションを再起動します。
+
+
+
+
+Taskオブジェクトをやり取りする機能を追加します。これを実現するには、
+
+
+
+
+ enumと、タスクを表すdata classを追加します:
+ Taskクラスには、kotlinx.serializationライブラリのSerializable型のアノテーションが付いていることに注意してください。これは、インスタンスをJSONとの間で変換でき、その内容をネットワーク経由で転送できることを意味します。
+ webSocketルートが追加されています。
+ .configureWebsockets()関数を次のように置き換えます:
+
+
+ contentConverterプロパティが設定され、プラグインがkotlinx.serializationライブラリを通じて送受信されるオブジェクトをシリアライズできるようになります。
+ Application.configureRouting()関数を以下の実装に置き換えます:
+
+
+ /tasksである単一のエンドポイントで構成されます。WebSocket型を使用しています。JavaScriptでこのオブジェクトを作成し、コンストラクタにエンドポイントのURLを渡します。その後、onopen、onclose、およびonmessageイベントのイベントハンドラーをアタッチします。onmessageイベントがトリガーされると、documentオブジェクトのメソッドを使用してテーブルに行を追加します。
+ )
+ をクリックしてアプリケーションを起動します。
+
+
+
+ Flowとして利用できます。
+ TaskRepository型を追加します:
+ TaskRepositoryを利用することで、Application.configureRouting()のルーティングを簡素化できます:
+
+
+ .configureRouting()メソッドを以下の実装に置き換えます:
+
+
+ routing {}ブロック内で、すべてのクライアントを追跡するためのスレッドセーフなsessionオブジェクトのリストを作成しました。
+ /tasks2の新しいエンドポイントを追加しました。クライアントがこのエンドポイントに接続すると、対応するsessionオブジェクトがリストに追加されます。その後、サーバーは新しいタスクの受信を待つ無限ループに入ります。新しいタスクを受信すると、サーバーはそれをリポジトリに保存し、現在のクライアントを含むすべてのクライアントにコピーを送信します。
+ sendTaskToServer()イベントハンドラーが呼び出されます。これにより、フォームデータを使用してJavaScriptオブジェクトが構築され、WebSocketオブジェクトの.send()メソッドを使用してサーバーに送信されます。
+ ) をクリックしてアプリケーションを再起動します。
+
+
+
+ )
+ をクリックしてGradleの変更をロードします。
+
+ 生成されたテストクラスを以下の実装に置き換えます: +
++ このセットアップで、以下のことを行いました: +
+Tasksのリストを宣言しました。
+ clientオブジェクトの.webSocket関数を使用して、/tasksにリクエストを送信しました。
+ Flowとして受け取り、それらをリストに順次追加しました。
+ expectedTasksとactualTasksを比較しました。
+ + お疲れ様でした!WebSocket通信とKtor Clientによる自動テストを組み込むことで、タスクマネージャーサービスを大幅に強化できました。 +
+
+
+ このトピックでは、既存のGradle/MavenプロジェクトにKtorサーバーに必要な依存関係を追加する方法を説明します。 +
++ Ktorの依存関係を追加する前に、このプロジェクトのリポジトリを設定する必要があります。 +
+
+
+ KtorのプロダクションリリースはMaven Centralリポジトリで利用可能です。 + ビルドスクリプトで以下のようにこのリポジトリを宣言できます。 +
+
+ プロジェクトはSuper POMからCentralリポジトリを継承しているため、
+
+ KtorのEAPバージョンにアクセスするには、Spaceリポジトリを参照する必要があります。 +
++ KtorのEAPにはKotlin devリポジトリが必要になる場合があることに注意してください。 +
++ すべてのKtorアプリケーションには、少なくとも以下の依存関係が必要です。 +
+
+ ktor-server-core: Ktorのコア機能が含まれています。
+
+ ktor-server-netty)の依存関係。
+
+ プラットフォームごとに、Ktorは-jvmなどのサフィックスを持つプラットフォーム固有のアーティファクトを提供しています(例: ktor-server-core-jvm、ktor-server-netty-jvm)。
+ Gradleは指定されたプラットフォームに適したアーティファクトを解決しますが、Mavenはこの機能をサポートしていないことに注意してください。
+ つまり、Mavenの場合はプラットフォーム固有のサフィックスを手動で追加する必要があります。
+ 基本的なKtorアプリケーションのdependenciesブロックは以下のようになります。
+
+ Ktorは、さまざまなロギングフレームワーク(例: LogbackやLog4j)のファサードとしてSLF4J APIを使用し、アプリケーションイベントをログに記録できるようにします。 + 必要なアーティファクトの追加方法については、ロガーの依存関係の追加を参照してください。 +
+
+ Ktorの機能を拡張する
+ Ktor Gradleプラグインを適用すると、暗黙的にKtor BOMの依存関係が追加され、すべてのKtorの依存関係が同じバージョンであることを保証できます。 + この場合、Ktorアーティファクトに依存する際にバージョンを指定する必要がなくなります。 +
++ 公開されたバージョンカタログを使用して、Ktorの依存関係の宣言を一元化することもできます。 + このアプローチには以下の利点があります。 +
+
+ カタログを宣言するには、
+ その後、カタログ名を参照してモジュールの
+ Gradle/Mavenを使用したKtorサーバーの
+ embeddedServerを使用する場合、メインクラスを次のように指定します。 +
++ EngineMainを使用する場合、それをメインクラスとして設定する必要があります。 + Nettyの場合、以下のようになります。 +
++ アプリケーションをFat JARとしてパッケージ化する場合は、対応するプラグインを設定する際にサーバーの作成方法も考慮する必要があります。 + 詳細については、以下のトピックを参照してください。 +
+
+
+
+ Ktorは、開発向けに特化した特別なモードを提供しています。このモードでは、以下の機能が有効になります: +
++ 開発モードはパフォーマンスに影響を与えるため、本番環境では使用しないでください。 +
++ 開発モードは、アプリケーションの設定ファイル、専用のシステムプロパティ、または環境変数を使用して、さまざまな方法で有効にできます。 +
+
+ developmentオプションをtrueに設定します:
+
+
+ IntelliJ IDEAを使用して開発モードでアプリケーションを実行するには、-Dフラグを付けてio.ktor.developmentをVMオプションに渡します:
+
+
+ ktorブロックを設定します:
+
+ Gradle CLIフラグを渡して、1回の実行に対して開発モードを有効にします: +
+
+ -eaフラグを使用して開発モードを有効にすることもできます。
+ -Dフラグで渡されるio.ktor.developmentシステムプロパティは、-eaよりも優先されることに注意してください。
+
+ Nativeクライアントで開発モードを有効にするには、io.ktor.development環境変数を使用します。
+
+
+ Ktor라는 이름은 ctor(생성자, constructor)라는 약어에서 유래되었으며, 첫 글자를 Kotlin의 'K'로 바꾼 것입니다.
+
+ Support 페이지에서 이용 가능한 지원 채널에 대해 자세히 알아보세요. + How to contribute 가이드는 Ktor에 기여할 수 있는 다양한 방법을 설명합니다. +
+
+ CIO는
+
+ 해당하는
+ EngineMain을 실행 중이라면 자동으로 처리됩니다.
+ 그렇지 않으면 직접 처리해야 합니다.
+ JVM의 Runtime.getRuntime().addShutdownHook 기능을 사용할 수 있습니다.
+
+ 프록시가 적절한 헤더를 제공하고 call.request.origin 속성은 원래 호출자(프록시)에 대한 연결 정보를 제공합니다.
+
+ jetbrains.space에서 Ktor 나이틀리 빌드(nightly build)를 받을 수 있습니다.
+ Early Access Program에서 더 자세한 내용을 확인하세요.
+
+ Ktor 버전이 포함된 Server 응답 헤더를 보내는
+ Ktor는 라우팅 결정을 문제 해결하는 데 도움이 되는 추적(tracing) 메커니즘을 제공합니다. + Tracing routes 섹션을 확인하세요. +
+
+ 이 오류는 사용자 본인 또는 플러그인이나 인터셉터(interceptor)가 이미 call.respond* 함수를 호출했으며, 이를 다시 호출하려고 함을 의미합니다.
+
+ 자세한 내용은
+ 이것은 Ktor가 resources 폴더에 설정 파일이 있는지, 그리고 resources 폴더가 제대로 지정되었는지 확인하세요.
+ 작동하는 프로젝트를 기반으로 시작하려면 Ktor 프로젝트 생성기 또는
+ IntelliJ IDEA Ultimate용 Ktor 플러그인을 사용하여 프로젝트를 구성하는 것이 좋습니다. 자세한 내용은
+ 네, Ktor 서버와 클라이언트는 적어도 Netty 엔진을 사용하면 Android 5 (API 21) 이상에서 작동하는 것으로 알려져 있습니다. +
+
+ CURL -I는 HEAD 요청을 수행하는 CURL --head의 별칭입니다.
+ 기본적으로 Ktor는 GET 핸들러에 대해 HEAD 요청을 처리하지 않습니다.
+ 이 기능을 활성화하려면
+ 가장 가능성 있는 원인은 백엔드가 리버스 프록시(reverse proxy) 또는 로드 밸런서(load balancer) 뒤에 있고, 이 중개 장치가 백엔드에 일반 HTTP 요청을 보내고 있기 때문입니다. 따라서 Ktor 백엔드 내부의 HttpsRedirect 플러그인은 이를 일반 HTTP 요청으로 간주하고 리다이렉트로 응답하게 됩니다.
+
+ 보통 리버스 프록시는 원래 요청에 대한 정보(예: HTTPS 여부 또는 원래 IP 주소)를 설명하는 헤더를 보내며,
+ Curl 클라이언트 엔진은
+ curl 라이브러리 설치가 필요합니다.
+ Windows의 경우 MinGW/MSYS2 curl 바이너리 사용을 고려해 볼 수 있습니다.
+
+ MinGW/MSYS2에 설명된 대로 MinGW/MSYS2를 설치합니다. +
+
+ 다음 명령어를 사용하여 libcurl을 설치합니다:
+
+ MinGW/MSYS2를 기본 위치에 설치했다면, PATH 환경 변수에
+
+ NoTransformationFoundException은 + *수신된 본문(received body)*에 대해 **결과(resulted)** 타입에서 클라이언트가 **기대하는(expected)** 타입으로의 적절한 변환을 찾을 수 없음을 나타냅니다. +
+
+ 요청의 Accept 헤더가 원하는 콘텐츠 타입을 지정하고 있는지, 그리고 서버 응답의 Content-Type 헤더가 클라이언트 측에서 기대하는 타입과 일치하는지 확인하세요.
+
+ 작업 중인 특정 콘텐츠 타입에 필요한 콘텐츠 변환을 등록하세요. +
++ 클라이언트 측에서 ContentNegotiation + 플러그인을 사용할 수 있습니다. + 이 플러그인을 사용하면 다양한 콘텐츠 타입에 대해 데이터를 직렬화(serialize) 및 역직렬화(deserialize)하는 방법을 지정할 수 있습니다. +
++ 필요한 모든 플러그인을 설치했는지 확인하세요. 누락되었을 수 있는 기능들: +
++ 코드 예제: + + %example_name% + +
+
+ Ktor는 멀티플랫폼 비동기 HTTP 클라이언트를 포함하고 있어,
+ 이 튜토리얼에서는 요청을 보내고 응답을 출력하는 첫 번째 Ktor 클라이언트 애플리케이션을 만드는 방법을 보여줍니다. +
++ 이 튜토리얼을 시작하기 전에, + IntelliJ IDEA Community 또는 + Ultimate를 설치하세요. +
+
+ 기존 프로젝트에서 Ktor 클라이언트를 수동으로
+ 새 Kotlin 프로젝트를 생성하려면, + IntelliJ IDEA를 열고 다음 단계를 따르세요: +
+
+ 시작 화면에서
+ 또는 메인 메뉴에서
+
+ 오른쪽 창에서 다음 설정을 지정합니다. +
+
+
+
+
+
+
+
+
+ Ktor 클라이언트에 필요한 의존성을 추가해 보겠습니다. +
+
+
+ Ktor의 EAP 버전을 사용하려면 Space 저장소(Space repository)를 추가해야 합니다. +
+
+
ktor-client-core는 핵심 클라이언트 기능을 제공하는 핵심 의존성입니다.
+ ktor-client-cio는 네트워크 요청을 처리하는
+
+
+ 클라이언트 구현을 추가하려면
+
+
+ Ktor에서 클라이언트는 HttpClient 클래스로 표현됩니다. +
+
+ HttpClient.get() 메서드를 사용하여 HttpResponse 클래스 객체로 수신됩니다.
+
+ 위의 코드를 추가한 후, IDE는 get() 함수에 대해 다음과 같은 에러를 표시합니다:
+
+
+ 이를 해결하려면 main() 함수를 중단 함수(suspending function)로 만들어야 합니다.
+
suspend 함수 호출에 대해 더 자세히 알아보려면 코루틴 기초(Coroutines basics)를 참조하세요.
+
+ IntelliJ IDEA에서 정의 옆의 빨간 전구를 클릭하고
+
+
+ println() 함수를 사용하여 서버에서 반환한 상태 코드(status code)를 출력하고, close() 함수를 사용하여 스트림을 닫고 이와 관련된 모든 리소스를 해제합니다.
+
+ 애플리케이션을 실행하려면
+
+ IntelliJ IDEA에서 main() 함수 옆의 거터(gutter) 아이콘을 클릭하고
+
+
+ IDE 하단의
+
+
+ 서버가 200 OK 메시지로 응답하지만, SLF4J가 StaticLoggerBinder 클래스를 찾는 데 실패하여 기본적으로 NOP(no-operation) 로거 구현을 사용한다는 에러 메시지도 표시될 것입니다. 이는 사실상 로깅이 비활성화되었음을 의미합니다.
+
+ 이제 작동하는 클라이언트 애플리케이션이 생성되었습니다. 하지만 이 경고를 해결하고 로깅을 통해 HTTP 호출을 디버깅하려면 추가 단계가 필요합니다. +
++ Ktor는 JVM에서 로깅을 위해 SLF4J 추상화 레이어를 사용하므로, 로깅을 활성화하려면 Logback과 같은 + 로깅 프레임워크를 제공해야 합니다. +
+
+
+
+ IntelliJ IDEA에서 다시 실행 버튼()을 클릭하여 애플리케이션을 다시 시작합니다.
+
+ 더 이상 에러가 표시되지 않아야 하며, IDE 하단의
+ 200 OK 메시지가 표시될 것입니다.
+
+ + 이제 로깅이 활성화되었습니다. 로그를 확인하려면 로깅 구성을 추가해야 합니다. +
+
+
+ IntelliJ IDEA에서 다시 실행 버튼()을 클릭하여 애플리케이션을 다시 시작합니다.
+
+ 이제
+
+ 이 구성을 더 잘 이해하고 확장하려면,
+ 코드 예제: + + %example_name% + +
++ Server-Sent Events (SSE)는 서버가 HTTP 연결을 통해 클라이언트에 지속적으로 이벤트를 푸시할 수 있도록 하는 기술입니다. 이는 클라이언트가 서버를 반복적으로 폴링(polling)할 필요 없이 서버가 이벤트 기반 업데이트를 보내야 하는 경우에 특히 유용합니다. +
++ Ktor에서 지원하는 SSE 플러그인은 서버와 클라이언트 간의 단방향 연결을 생성하는 간단한 방법을 제공합니다. +
+서버 측 지원을 위한 SSE 플러그인에 대해 자세히 알아보려면
+
+ SSE는
+ SSE 플러그인을 설치하려면, 클라이언트 구성 블록 내부의 install 함수에 전달하세요:
+
+ 선택적으로 install 블록 내에서
+ SSEConfig
+ 클래스의 지원되는 속성을 설정하여 SSE 플러그인을 구성할 수 있습니다.
+
+ 자동 재연결을 활성화하려면 maxReconnectionAttempts를 0보다 큰 값으로 설정하세요. reconnectionTime을 사용하여 시도 간의 지연 시간을 구성할 수도 있습니다:
+
+ 서버와의 연결이 끊어지면 클라이언트는 재연결을 시도하기 전에 지정된 reconnectionTime 동안 기다립니다. 연결을 재설정하기 위해 지정된 maxReconnectionAttempts 횟수까지 시도합니다.
+
+ 다음 예제에서는 SSE 플러그인을 HTTP 클라이언트에 설치하고, 수신 플로우(flow)에 주석만 포함된 이벤트와 retry 필드만 포함된 이벤트를 포함하도록 구성합니다:
+
+ SSE 응답은 본질적으로 스트리밍 방식이므로 전체 본문을 캡처하는 것이 현실적이지 않습니다. SSE 스트림이 실패할 때 응답 본문을 안전하게 검색하기 위해 진단 버퍼를 활성화할 수 있습니다. 버퍼에는 이미 처리된 데이터만 포함되며(네트워크에서 다시 읽지 않음), 실패 시 로깅 및 오류 분석을 위한 용도입니다. +
++ 호출별로 버퍼를 구성할 수도 있습니다: +
+
+ SSEBufferPolicy 타입은 처리된 SSE 데이터를 저장하기 위한 여러 전략을 제공합니다. 이 정책들은 메모리에 유지되는 스트림의 양과 오류 발생 시 사용 가능한 양을 제어합니다.
+
Off (기본값)LastLines(n)LastEventLastEvents(n)All
+ 실패 시 네트워크에서 다시 읽지 않고 response?.bodyAsText()를 사용하여 버퍼에 접근할 수 있습니다.
+
+ 클라이언트의 SSE 세션은
+
+ ClientSSESession
+
+ 인터페이스로 표현됩니다. 이 인터페이스는 서버로부터 서버 전송 이벤트를 받을 수 있는 API를 노출합니다.
+
HttpClient를 사용하면 다음 방법 중 하나로 SSE 세션에 접근할 수 있습니다:
sse()
+
+ 함수는 SSE 세션을 생성하고 해당 세션에서 동작할 수 있게 합니다.
+ sseSession()
+
+ 함수는 SSE 세션을 열 수 있게 합니다.
+ URL 엔드포인트를 지정하기 위해 다음 두 가지 옵션 중 선택할 수 있습니다:
+urlString 파라미터를 사용하여 전체 URL을 문자열로 지정합니다.schema, host, port, path 파라미터를 사용하여 각각 프로토콜 스킴, 도메인 이름, 포트 번호, 경로 이름을 지정합니다.ClientSSESession 및 ClientSSESessionWithDeserialization 인스턴스는 세션이 유지되는 동안에만 유효합니다. serverSentEvents { ... } 블록이 완료되거나 연결이 닫히면 해당 스코프는 자동으로 취소됩니다.
+ 선택적으로 연결을 구성하기 위해 다음 파라미터들을 사용할 수 있습니다:
+reconnectionTimeshowCommentEventsshowRetryEventsretry 필드만 포함된 이벤트를 표시할지 여부를 지정합니다.
+ deserializeTypedServerSentEvent의 data 필드를 객체로 변환하는 역직렬화 함수입니다. 자세한 내용은 역직렬화(Deserialization)를 참조하세요.
+
+ 람다 인자 내에서는
+ ClientSSESession
+ 컨텍스트에 접근할 수 있습니다. 블록 내에서 다음 속성을 사용할 수 있습니다:
+
callHttpClientCall입니다.
+ incoming
+ 아래 예제는 events 엔드포인트로 새로운 SSE 세션을 생성하고, incoming 속성을 통해 이벤트를 읽고 수신된
+ ServerSentEvent를 출력합니다.
+
전체 예제는 + client-sse를 참조하세요. +
++ SSE 플러그인은 서버 전송 이벤트를 타입 안정성이 보장된 Kotlin 객체로 역직렬화하는 기능을 지원합니다. 이 기능은 서버의 구조화된 데이터로 작업할 때 특히 유용합니다. +
+
+ 역직렬화를 활성화하려면 SSE 접근 함수에서 deserialize 파라미터를 사용하여 커스텀 역직렬화 함수를 제공하고,
+
+ ClientSSESessionWithDeserialization
+
+ 클래스를 사용하여 역직렬화된 이벤트를 처리하세요.
+
+ 다음은 kotlinx.serialization을 사용하여 JSON 데이터를 역직렬화하는 예제입니다:
+
전체 예제는 + client-sse를 참조하세요. +
+
+ 필수 의존성: io.ktor:ktor-client-websockets
+
+ 코드 예제: + + %example_name% + +
+클라이언트용 Websockets 플러그인을 사용하면 서버와 메시지를 교환하기 위한 WebSocket 세션을 처리할 수 있습니다.
+모든 엔진이 WebSocket을 지원하는 것은 아닙니다. 지원되는 엔진에 대한 개요는 제한 사항(Limitations)을 참조하세요.
+서버 측의 WebSocket 지원에 대해 알아보려면
WebSockets를 사용하려면 빌드 스크립트에 %artifact_name% 아티팩트를 포함해야 합니다:
WebSockets 플러그인을 설치하려면, 클라이언트 설정 블록 내의 install 함수에 전달하세요:
선택 사항으로, install 블록 내에서 WebSockets.Config의 지원되는 속성들을 전달하여 플러그인을 설정할 수 있습니다.
+
maxFrameSizeFrame 크기를 설정합니다.
+ contentConverterpingIntervalMillisLong 형식으로 핑(ping) 사이의 간격을 지정합니다.
+ pingIntervalDuration 형식으로 핑 사이의 간격을 지정합니다.
+ pingInterval 및 pingIntervalMillis 속성은 OkHttp 엔진에는 적용되지 않습니다. OkHttp의 핑 간격을 설정하려면 엔진 설정을 사용할 수 있습니다:
+
+ 다음 예제에서는 핑 프레임을 자동으로 전송하고 WebSocket 연결을 유지하기 위해 WebSockets 플러그인을 20초(20_000 밀리초)의 핑 간격으로 설정합니다:
+
클라이언트의 WebSocket 세션은 DefaultClientWebSocketSession 인터페이스로 표현됩니다. 이 인터페이스는 WebSocket 프레임을 주고받고 세션을 닫을 수 있는 API를 제공합니다. +
+
+ HttpClient는 WebSocket 세션에 액세스하는 두 가지 주요 방법을 제공합니다:
+
webSocket()
+ 함수는 DefaultClientWebSocketSession을 블록 인자로 받습니다.
DefaultClientWebSocketSession 인스턴스를 반환하며, runBlocking 또는 launch 스코프 외부에서 세션에 액세스할 수 있게 해줍니다.
+ 함수 블록 내에서 지정된 경로에 대한 핸들러를 정의합니다. 블록 내에서는 다음과 같은 함수와 속성을 사용할 수 있습니다:
+send()send() 함수를 사용하여 서버에 텍스트 콘텐츠를 보냅니다.
+ outgoingoutgoing 속성을 사용하여 WebSocket 프레임을 보내기 위한 채널에 액세스합니다. 프레임은 Frame 클래스로 표현됩니다.
+ incomingincoming 속성을 사용하여 WebSocket 프레임을 받기 위한 채널에 액세스합니다. 프레임은 Frame 클래스로 표현됩니다.
+ close()close() 함수를 사용하여 지정된 사유와 함께 종료(close) 프레임을 보냅니다.
+ + WebSocket 프레임의 유형을 검사하고 그에 따라 처리할 수 있습니다. 주요 프레임 유형은 다음과 같습니다: +
+Frame.Text는 텍스트 프레임을 나타냅니다. 콘텐츠를 읽으려면
+ Frame.Text.readText()를 사용하세요.
+ Frame.Binary는 바이너리 프레임을 나타냅니다. 콘텐츠를 읽으려면 Frame.Binary.readBytes()를 사용하세요.
+ Frame.Close는 종료 프레임을 나타냅니다. 세션 종료 사유를 가져오려면 Frame.Close.readReason()을 사용하세요.
+ 아래 예제는 echo WebSocket 엔드포인트를 생성하고 서버와 메시지를 주고받는 방법을 보여줍니다.
전체 예제는 + client-websockets를 참조하세요. +
+
+
+
이 주제에서는 Docker Compose 환경에서 Ktor 서버 애플리케이션을 실행하는 방법을 살펴봅니다. 여기서는
+ 데이터베이스 연결 구성 튜토리얼에서 생성된 프로젝트는 데이터베이스 연결을 설정하기 위해 하드코딩된 속성을 사용합니다.
+
+ PostgreSQL 데이터베이스의 연결 설정을
+ ktor 그룹 외부에 storage 그룹을 추가합니다:
+
이 설정들은 나중에
+
+ configureDatabases() 함수를 업데이트합니다:
+
+ 이제 configureDatabases() 함수는 ApplicationConfig를 매개변수로 받아 config.property를 사용해 사용자 정의 설정을 로드합니다.
+
+ configureDatabases()에 environment.config를 전달합니다:
+
Docker에서 실행하려면 애플리케이션의 모든 필수 파일이 컨테이너에 배포되어야 합니다. 사용하는 빌드 시스템에 따라 이를 수행하는 다양한 플러그인이 있습니다:
+이 예제에서는
+ 애플리케이션을 도커화(Dockerize)하려면, 프로젝트의 루트 디렉터리에 새
+ 이 예제에서는 Amazon Corretto Docker 이미지를 사용하지만, 다음과 같은 다른 적절한 대안으로 교체할 수 있습니다: +
+프로젝트 루트 디렉터리에 새
web 서비스는 이미지 내부에 패키징된 Ktor 애플리케이션을 실행하는 데 사용됩니다.
+ db 서비스는 postgres 이미지를 사용하여 태스크를 저장하기 위한 ktor_tutorial_db 데이터베이스를 생성합니다.
+ + Ktor 애플리케이션이 포함된 fat JAR를 생성하려면 다음 명령을 실행합니다: +
+
+ docker compose up 명령을 사용하여 이미지를 빌드하고 컨테이너를 시작합니다:
+
+ http://localhost:8080/static/index.html로 이동하여 웹 애플리케이션을 엽니다. 태스크를 필터링하고 새로 추가하기 위한 세 개의 폼과 태스크 목록 테이블이 포함된 Task Manager Client 페이지가 표시되어야 합니다. +
+
+ + 코드 예제: + + %example_name% + +
+
+ 사용된 플러그인:
+ 이 문서에서는 Ktor를 활용하여 원활한 데이터 처리를 구현하면서 Android, iOS, 웹 및 데스크톱 플랫폼에서 실행되는 Kotlin 기반 풀스택 애플리케이션을 개발하는 방법을 배웁니다. +
+이 튜토리얼을 마치면 다음 사항을 수행할 수 있게 됩니다:
+
+ 이전 튜토리얼들에서는 할 일 관리자(Task Manager) 예제를 사용하여
+
+ 이제 표시할 데이터를 가져오기 위해 Ktor 서비스를 사용하는 Android, iOS, 웹 및 데스크톱 플랫폼용 클라이언트를 만들 것입니다. 가능한 한 클라이언트와 서버 간에 데이터 타입을 공유하여 개발 속도를 높이고 오류 발생 가능성을 줄일 것입니다. +
++ 이전 문서들과 마찬가지로 IntelliJ IDEA를 IDE로 사용합니다. 환경 설치 및 구성에 대해서는 + + Kotlin Multiplatform 퀵스타트 + 를 참조하세요. +
++ Compose Multiplatform을 처음 사용하는 경우, 이 튜토리얼을 시작하기 전에 + + Compose Multiplatform 시작하기 + 튜토리얼을 먼저 완료하는 것을 권장합니다. 작업의 복잡도를 줄이기 위해 단일 클라이언트 플랫폼에 집중할 수도 있습니다. 예를 들어 iOS를 사용해 본 적이 없다면 데스크톱이나 Android 개발에 집중하는 것이 현명할 수 있습니다. +
++ Ktor 프로젝트 생성기 대신 IntelliJ IDEA의 Kotlin Multiplatform 프로젝트 위저드(Wizard)를 사용합니다. + 이를 통해 클라이언트와 서비스를 확장해 나갈 수 있는 기본 멀티플랫폼 프로젝트가 생성됩니다. 클라이언트는 SwiftUI와 같은 네이티브 UI 라이브러리를 사용할 수도 있지만, 이 튜토리얼에서는 Compose Multiplatform을 사용하여 모든 플랫폼을 위한 공유 UI를 만들 것입니다. +
+
+ 대상 플랫폼으로
+
+ Mac을 사용 중이라면
+
+
+
+
+
+ 브라우저에서 http://0.0.0.0:8080/로 접속하여 애플리케이션을 엽니다.
+ 브라우저에 Ktor가 표시하는 메시지가 나타나야 합니다.
+
+
+
+
+
+ sayHello() 함수를 호출하는 것을 볼 수 있습니다:
+
+ sayHello() 함수는
+ sayHello() 함수가 그곳에서도 사용되고 있음을 확인할 수 있습니다:
+
+
+
+ 예를 들어, Greeting 타입에서 현재 플랫폼의 이름은 기대(expected) 및 실제(actual) 선언을 통해 플랫폼별 API를 사용하여 가져옵니다.
+
+ getPlatform() 함수는 expect 키워드와 함께 선언되어 있습니다:
+
+ 그런 다음 아래와 같이 각 대상 플랫폼은 getPlatform() 함수의 actual 선언을 제공합니다:
+
+ 대상 플랫폼에 대한 실행 구성을 실행하여 클라이언트 애플리케이션을 구동할 수 있습니다. iOS 시뮬레이터에서 애플리케이션을 실행하려면 아래 단계를 따르세요: +
+
+
+ iOS 앱을 실행하면 내부적으로 Xcode로 빌드되어 iOS 시뮬레이터에서 실행됩니다.
+ 앱에는 클릭 시 이미지를 토글하는 버튼이 표시됩니다.
+
+
+ 버튼을 처음 누르면 현재 플랫폼의 세부 정보가 텍스트에 추가됩니다. 이를 구현하는 코드는
+
+ 이것은 Composable 함수이며, 이 문서의 뒷부분에서 수정할 예정입니다. 지금 중요한 것은 이것이 UI를 표시하고 공유 Greeting 타입을 활용하며, 이 타입은 다시 공통 Platform 인터페이스를 구현하는 플랫폼별 클래스를 사용한다는 점입니다.
+
+ 생성된 프로젝트의 구조를 이해했으므로, 이제 할 일 관리자 기능을 점진적으로 추가할 수 있습니다. +
++ 먼저 모델 타입을 추가하고 클라이언트와 서버 모두에서 접근 가능한지 확인합니다. +
+kotlinx.serialization 의존성을 정의합니다:
+
+
+ 같은 파일에서
+ 우선순위를 나타내는 enum과 할 일을 나타내는 클래스를 추가합니다.
+ Task 클래스는 kotlinx.serialization 라이브러리의
+ Serializable 어노테이션을 가집니다:
+
+ 다음 단계는 할 일 관리자를 위한 서버 구현을 만드는 것입니다. +
+
+ 이 패키지 안에
+ 같은 패키지에
+
+ 이 구현은 단순화를 위해 모든 라우팅 코드를 Application.module() 함수 안에 배치했다는 점을 제외하면 이전 튜토리얼의 내용과 매우 유사합니다.
+
+ 이 코드를 입력하고 임포트를 추가하면 컴파일 에러가 여러 개 발생할 것입니다. 이는 코드에서 웹 클라이언트와의 상호 작용을 위한
+ 서버 모듈 빌드 파일(
ContentNegotiation 타입과 json() 함수에 대한 임포트가 정상적으로 작동하는 것을 확인할 수 있습니다.
+ + 클라이언트가 서버에 접근할 수 있도록 하려면 Ktor Client를 포함해야 합니다. 여기에는 세 가지 유형의 의존성이 관련됩니다: +
+
+ 이 작업이 완료되면 클라이언트에서 Ktor Client를 감싸는 얇은 래퍼(wrapper) 역할을 할 TaskApi 타입을 추가할 수 있습니다.
+
+ 새 패키지 안에 클라이언트 설정을 위한
+ 1.2.3.4를 현재 머신의 IP 주소로 바꾸세요. Android 가상 장치나 iOS 시뮬레이터에서 실행되는 코드에서는 0.0.0.0 또는 localhost로 호출할 수 없습니다.
+
IP 주소 찾기:
+
+ 모바일 시뮬레이터는 localhost에 도달할 수 없으므로 머신의 실제 IP 주소가 필요합니다. IP 주소를 확인하려면 다음 명령어 중 하나를 실행하세요:
+
ifconfig | grep "inet " | grep -v 127.0.0.1hostname -I | awk '{print $1}'ipconfig 실행 후 "IPv4 Address" 확인
+ 같은
+ TaskApi 타입을 사용하여 서버에서 할 일 목록을 가져온 다음, 각 할 일의 이름을 컬럼(Column)에 표시합니다:
+
+ 서버가 실행 중인 상태에서
+
+
+ Android 플랫폼에서는 애플리케이션에 네트워킹 권한을 명시적으로 부여하고 일반 텍스트(cleartext) 데이터를 주고받을 수 있도록 허용해야 합니다. 이 권한을 활성화하려면
+
+
+
+ 데스크톱 클라이언트의 경우, 창에 크기와 타이틀을 지정할 것입니다.
+ title을 변경하고 state 속성을 설정하여 코드를 수정합니다:
+
+
+
+ 다음 실행 구성 중 하나를 사용하여 웹 클라이언트를 실행합니다: +
+
+ + 이제 클라이언트가 서버와 통신하고 있지만, 아직 매력적인 UI라고 하기는 어렵습니다. +
+
+ App을 아래의 App 및 TaskCard
+ Composable로 교체합니다:
+
+ 이 구현을 통해 클라이언트는 기본적인 기능을 갖추게 되었습니다. +
+
+ LaunchedEffect 타입을 사용하여 시작 시 모든 할 일을 로드하고, LazyColumn
+ Composable을 사용하여 사용자가 할 일 목록을 스크롤할 수 있게 했습니다.
+
+ 마지막으로 별도의 TaskCard Composable을 만들어 Card를 사용하여 각 Task의 세부 정보를 표시했습니다. 할 일을 삭제하거나 업데이트하기 위한 버튼들도 추가되었습니다.
+
+ 클라이언트 애플리케이션(예: Android 앱)을 다시 실행합니다.
+ 이제 할 일 목록을 스크롤하고 세부 정보를 확인하며 삭제할 수 있습니다:
+
+
+ 클라이언트를 완성하기 위해 할 일의 세부 정보를 업데이트할 수 있는 기능을 통합합니다. +
+
+ 아래와 같이 UpdateTaskDialog Composable과 필요한 임포트를 추가합니다:
+
+ 이 Composable은 다이얼로그 박스로 Task의 세부 정보를 표시합니다. description과
+ priority는 TextField Composable 안에 배치되어 업데이트가 가능합니다. 사용자가 업데이트 버튼을 누르면 onConfirm() 콜백이 호출됩니다.
+
+ 같은 파일에서 App Composable을 업데이트합니다:
+
+ 선택된 현재 할 일을 저장하기 위해 추가적인 상태(state)를 관리합니다. 이 값이 null이 아니면 UpdateTaskDialog Composable을 호출하고, onConfirm() 콜백이 TaskApi를 사용하여 서버에 POST 요청을 보내도록 설정합니다.
+
+ 마지막으로 TaskCard Composable을 생성할 때 onUpdate() 콜백을 사용하여 currentTask 상태 변수를 설정합니다.
+
+ + 이 문서에서는 Kotlin Multiplatform 애플리케이션의 맥락 내에서 Ktor를 사용해 보았습니다. 이제 다양한 플랫폼을 대상으로 하는 여러 서비스와 클라이언트가 포함된 프로젝트를 만들 수 있습니다. +
+
+ 살펴보았듯이 코드 중복이나 낭비 없이 기능을 구축할 수 있습니다. 프로젝트의 모든 계층에서 필요한 타입은
+
+ 이러한 방식의 개발은 클라이언트와 서버 기술 모두에 대한 지식이 필요합니다. 하지만 Kotlin Multiplatform 라이브러리와 Compose Multiplatform을 사용하면 새로 배워야 할 내용의 양을 최소화할 수 있습니다. 처음에는 단일 플랫폼에만 집중하더라도 애플리케이션에 대한 수요가 늘어남에 따라 다른 플랫폼을 쉽게 추가할 수 있습니다. +
++ 코드 예제: + migrating-express + migrating-express-ktor +
++ 이 가이드에서는 애플리케이션 생성과 첫 번째 애플리케이션 작성부터 애플리케이션 기능을 확장하기 위한 미들웨어 생성에 이르기까지, 기본적인 시나리오에서 Express 애플리케이션을 Ktor로 마이그레이션하는 방법을 살펴보겠습니다. +
+|
+ |
+
+
+ |
+
|
+ |
+
+ + Ktor는 애플리케이션 스켈레톤을 생성하는 다음과 같은 방법들을 제공합니다: + +
+Ktor Project Generator — 웹 기반 생성기를 사용합니다. + +
+
+ Ktor CLI 도구
+ — + + Yeoman generator + + — 대화형으로 프로젝트 설정을 구성하고 필요한 플러그인을 선택합니다: + ++IntelliJ IDEA Ultimate — 내장된 Ktor 프로젝트 마법사를 사용합니다. + +
+ 자세한 지침은 |
+
+ 이 섹션에서는 GET 요청을 수락하고 미리 정의된 평문 텍스트로 응답하는 가장 간단한 서버 애플리케이션을 만드는 방법을 살펴보겠습니다.
+
|
+ |
+
+
+ 아래 예제는 서버를 시작하고 + 전체 예제는 + 1_hello + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+ + Ktor에서는 코드 내에서 서버 파라미터를 구성하고 애플리케이션을 빠르게 실행하기 위해 embeddedServer 함수를 사용할 수 있습니다. + ++ 전체 예제는 + 1_hello + 프로젝트를 참조하세요. + ++ HOCON 또는 YAML 형식을 사용하는 외부 구성 파일에서 서버 설정을 지정할 수도 있습니다. + + |
+
+ 위의 Express 애플리케이션은 다음과 같은
+ Ktor에서 각 응답에 기본
+ 이 섹션에서는 Express와 Ktor에서 이미지, CSS 파일, JavaScript 파일과 같은 정적 파일을 제공하는 방법을 살펴보겠습니다. 메인
|
+ |
+
+
+ Express에서는 + 전체 예제는 + 2_static + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor에서는 + 전체 예제는 2_static + 프로젝트를 참조하세요. + + |
+
+ 정적 콘텐츠를 제공할 때 Express는 다음과 같은 몇 가지 응답 헤더를 추가합니다: +
++ Ktor에서 이러한 헤더를 관리하려면 다음 플러그인들을 설치해야 합니다: +
+
+
+
+
+ GET, POST 등)와 경로로 정의된 특정 엔드포인트로 들어오는 요청을 처리할 수 있게 해줍니다. 아래 예제는 GET 및 POST 요청을 처리하는 방법을 보여줍니다.
+
|
+ |
+
+ + 전체 예제는 + 3_router + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ + 전체 예제는 + 3_router + 프로젝트를 참조하세요. + + |
+
+ 다음 예제는 경로별로 라우트 핸들러를 그룹화하는 방법을 보여줍니다. +
+|
+ |
+
+
+ Express에서는 + 전체 예제는 + 3_router + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor는 + 전체 예제는 + 3_router + 프로젝트를 참조하세요. + + |
+
+ 두 프레임워크 모두 단일 파일에서 관련 라우트를 그룹화할 수 있습니다. +
+|
+ |
+
+
+ Express는 마운트 가능한 라우트 핸들러를 만들기 위해 + 전체 예제는 + 3_router + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor에서 일반적인 패턴은 + 전체 예제는 + 3_router + 프로젝트를 참조하세요. + + |
+
+ URL 경로를 문자열로 지정하는 것 외에도, Ktor는
+ 이 섹션에서는 라우트 및 쿼리 파라미터에 접근하는 방법을 보여줍니다. +
++ 라우트(또는 경로) 파라미터는 URL에서 해당 위치에 지정된 값을 캡처하는 데 사용되는 명명된 URL 세그먼트입니다. +
+|
+ |
+
+
+ Express에서 라우트 파라미터에 접근하려면 + 전체 예제는 + 4_parameters + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor에서 라우트 파라미터는 + 전체 예제는 + 4_parameters + 프로젝트를 참조하세요. + + |
+
+ 아래 표는 쿼리 스트링의 파라미터에 접근하는 방법을 비교합니다. +
+|
+ |
+
+
+ Express에서 라우트 파라미터에 접근하려면 + 전체 예제는 + 4_parameters + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor에서 라우트 파라미터는 + 전체 예제는 + 4_parameters + 프로젝트를 참조하세요. + + |
+
+ 이전 섹션들에서 평문 텍스트 콘텐츠로 응답하는 방법을 이미 살펴보았습니다. 이제 JSON, 파일 및 리다이렉션 응답을 보내는 방법을 살펴보겠습니다. +
+|
+ |
+
+
+ Express에서 적절한 콘텐츠 타입으로 JSON 응답을 보내려면 + 전체 예제는 + 5_send_response + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor에서는
+ 데이터를 JSON으로 직렬화하려면
+ 그런 다음, + 전체 예제는 + 5_send_response + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Express에서 파일로 응답하려면 + 전체 예제는 + 5_send_response + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor는 클라이언트에 파일을 전송하기 위해 + 전체 예제는 + 5_send_response + 프로젝트를 참조하세요. + + |
+
+ Express 애플리케이션은 파일로 응답할 때
|
+ |
+
+
+ + 전체 예제는 + 5_send_response + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor에서는 파일을 첨부 파일로 전송하기 위해 + 전체 예제는 + 5_send_response + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Express에서 리다이렉션 응답을 생성하려면 + 전체 예제는 + 5_send_response + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor에서는 + 전체 예제는 + 5_send_response + 프로젝트를 참조하세요. + + |
+
+ Express와 Ktor 모두 뷰 작업을 위한 템플릿 엔진을 사용할 수 있습니다. +
+|
+ |
+
+
+
+ 이 템플릿으로 응답하려면 + 전체 예제는 + 6_templates + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor는 FreeMarker, Velocity 등 여러 + 전체 예제는 + 6_templates + 프로젝트를 참조하세요. + + |
+
+ 이 섹션에서는 다양한 형식의 요청 본문을 수신하는 방법을 보여줍니다. +
+
+ 아래 POST 요청은 서버로 텍스트 데이터를 보냅니다:
+
+ 서버 측에서 이 요청의 본문을 평문 텍스트로 수신하는 방법을 살펴보겠습니다. +
+|
+ |
+
+
+ Express에서 들어오는 요청 본문을 파싱하려면
+ + 전체 예제는 + 7_receive_request + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor에서는 + 전체 예제는 + 7_receive_request + 프로젝트를 참조하세요. + + |
+
+ 이 섹션에서는 JSON 본문을 수신하는 방법을 살펴보겠습니다. 아래 샘플은 본문에 JSON 객체가 포함된 POST 요청을 보여줍니다:
+
|
+ |
+
+
+ Express에서 JSON을 수신하려면 + 전체 예제는 + 7_receive_request + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor에서는 + 수신된 데이터를 객체로 역직렬화하려면 데이터 클래스를 생성해야 합니다: + +
+ 그런 다음, 이 데이터 클래스를 파라미터로 받는 + 전체 예제는 + 7_receive_request + 프로젝트를 참조하세요. + + |
+
+ 이제 POST 요청을 보여줍니다:
+
|
+ |
+
+
+ 평문 텍스트 및 JSON과 마찬가지로, Express에는 + 전체 예제는 + 7_receive_request + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor에서는 + 전체 예제는 + 7_receive_request + 프로젝트를 참조하세요. + + |
+
+ 다음 유스케이스는 바이너리 데이터를 처리하는 것입니다. 아래 요청은
|
+ |
+
+
+ Express에서 바이너리 데이터를 처리하려면 파서 타입을 + 전체 예제는 + 7_receive_request + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor는 바이트 시퀀스를 비동기적으로 읽고 쓰기 위해 + 전체 예제는 + 7_receive + request + 프로젝트를 참조하세요. + + |
+
+ 마지막 섹션에서는 POST 요청은
|
+ |
+
+
+ Express에서는 멀티파트 데이터를 파싱하기 위해 별도의 모듈이 필요합니다. 아래 예제에서는 서버에 파일을 업로드하기 위해 + 전체 예제는 + 7_receive_request + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor에서 멀티파트 요청의 일부로 전송된 파일을 수신해야 하는 경우, + 전체 예제는 + 7_receive_request + 프로젝트를 참조하세요. + + |
+
+ 마지막으로 살펴볼 내용은 서버 기능을 확장할 수 있는 미들웨어를 만드는 방법입니다. 아래 예제는 Express와 Ktor를 사용하여 요청 로깅을 구현하는 방법을 보여줍니다. +
+|
+ |
+
+
+ Express에서 미들웨어는 + 전체 예제는 + 8_middleware + 프로젝트를 참조하세요. + + |
+
|
+ |
+
+
+ Ktor는 + 전체 예제는 + 8_middleware + 프로젝트를 참조하세요. + + |
+
+ 이 가이드에서 다루지 않은 세션 관리, 권한 부여, 데이터베이스 통합 등 더 많은 유스케이스가 있습니다. 이러한 대부분의 기능에 대해 Ktor는 애플리케이션에 설치하고 필요에 따라 구성할 수 있는 전용 플러그인을 제공합니다. Ktor에 대해 더 자세히 알아보려면 단계별 가이드와 바로 사용할 수 있는 샘플들을 제공하는
+ 코드 예제: + autoreload-engine-main, + autoreload-embedded-server +
+
+ 개발 중에 서버를
+ 개발 모드 활성화 +
++ (선택 사항) 감시 경로(watch paths) 구성 +
++ 변경 시 재컴파일 활성화 +
+| 모듈 유형 | +<= 3.2 | +> 3.2 | +
| 람다 초기화(Lambda initializer) | +❌ 지원되지 않음 | +❌ 지원되지 않음 | +
| 블로킹 함수 참조(Blocking function reference) | +✅ 지원됨 | +❌ 지원되지 않음 | +
| 서스펜드 함수 참조(Suspend function reference) | +❌ 지원되지 않음 | +✅ 지원됨 | +
| 설정 참조(Config reference) | +✅ 지원됨 | +✅ 지원됨 | +
+ 오토 리로드를 사용하려면 먼저 개발 모드를 활성화해야 합니다.
+ 이는
+ EngineMain을 사용하여 서버를 실행하는 경우, 설정 파일에서 개발 모드를 활성화하세요.
+
+ embeddedServer를 사용하여 서버를 실행하는 경우, io.ktor.development 시스템 속성을 사용할 수 있습니다.
+
+ 개발 모드가 활성화되면 Ktor는 작업 디렉터리의 출력 파일을 자동으로 감시합니다. + 필요한 경우, 감시 경로를 지정하여 감시할 폴더 세트를 좁힐 수 있습니다. +
+
+ 개발 모드를 활성화하면 Ktor는 작업 디렉터리의 출력 파일을 감시하기 시작합니다.
+ 예를 들어, Gradle로 빌드된
+ 감시 경로(Watch paths)를 사용하면 감시할 폴더 세트를 좁힐 수 있습니다.
+ 이를 위해 감시할 경로의 일부를 지정할 수 있습니다.
+ 예를 들어, classes를 전달합니다.
+ 서버를 실행하는 방식에 따라 다음과 같은 방법으로 감시 경로를 지정할 수 있습니다.
+
+ watch 옵션을 지정합니다.
+
+ 다음과 같이 여러 감시 경로를 지정할 수도 있습니다. +
++ 전체 예제는 여기에서 확인할 수 있습니다: autoreload-engine-main. +
+
+ embeddedServer를 사용하는 경우, watchPaths 매개변수로 감시 경로를 전달합니다.
+
+ 전체 예제는 autoreload-embedded-server를 참조하세요. +
+
+ 오토 리로드는 출력 파일의 변경 사항을 감지하므로, 프로젝트를 다시 빌드해야 합니다.
+ IntelliJ IDEA에서 수동으로 다시 빌드하거나 Gradle의 -t 명령줄 옵션을 사용하여 연속 빌드 실행(continuous build execution)을 활성화할 수 있습니다.
+
+ IntelliJ IDEA에서 프로젝트를 수동으로 다시 빌드하려면 메인 메뉴에서
+ Gradle을 사용하여 프로젝트를 자동으로 다시 빌드하려면 터미널에서 -t 옵션과 함께 build 태스크를 실행하면 됩니다.
+
+ 프로젝트를 다시 로드할 때 테스트 실행을 건너뛰려면 build 태스크에 -x 옵션을 전달할 수 있습니다.
+
+ Ktor를 사용하면 호스트 주소, 포트,
+ embeddedServer를 사용하면 원하는 파라미터를 함수에 직접 전달하여 서버를 설정합니다.
+
+ embeddedServer
+
+ 함수는
+ 이 섹션에서는 embeddedServer를 실행하는 여러 가지 예시를 살펴보며 서버를 유용하게 설정하는 방법을 설명합니다.
+
+ 아래 코드 스니펫은 Netty 엔진과 8080 포트를 사용하는 기본 서버 설정을 보여줍니다.
+
+ port 파라미터를 0으로 설정하면 서버를 무작위 포트에서 실행할 수 있습니다.
+ embeddedServer 함수는 엔진 인스턴스를 반환하므로,
+
+ ApplicationEngine.resolvedConnectors
+
+ 함수를 사용하여 코드에서 포트 값을 가져올 수 있습니다.
+
+ embeddedServer 함수를 사용하면 configure 파라미터를 통해 엔진 전용 옵션을 전달할 수 있습니다. 이 파라미터에는 모든 엔진에 공통적인 옵션이 포함되어 있으며,
+
+ ApplicationEngine.Configuration
+
+ 클래스에 의해 노출됩니다.
+
+ 아래 예시는 Netty 엔진을 사용하여 서버를 설정하는 방법을 보여줍니다.
+ configure 블록 내에서 호스트와 포트를 지정하기 위한 connector를 정의하고 다양한 서버 파라미터를 커스터마이징합니다.
+
+ connectors.add() 메서드는 지정된 호스트(127.0.0.1)와 포트(8080)로 커넥터(connector)를 정의합니다.
+
이러한 옵션 외에도 다른 엔진 전용 속성을 설정할 수 있습니다.
++ Netty 전용 옵션은 + + NettyApplicationEngine.Configuration + + 클래스에 의해 노출됩니다. +
++ Jetty 전용 옵션은 + + JettyApplicationEngineBase.Configuration + + 클래스에 의해 노출됩니다. +
++ + configureServer + + 블록 내에서 Jetty 서버를 설정할 수 있으며, 이 블록은 + Server + 인스턴스에 대한 접근을 제공합니다. +
+
+ idleTimeout 속성을 사용하여 연결이 닫히기 전까지 유휴 상태로 유지될 수 있는 시간을 지정합니다.
+
CIO 전용 옵션은 + + CIOApplicationEngine.Configuration + + 클래스에 의해 노출됩니다. +
+Tomcat을 엔진으로 사용하는 경우, + + configureTomcat + + 속성을 사용하여 설정할 수 있으며, 이 속성은 + Tomcat + 인스턴스에 대한 접근을 제공합니다. +
++ 아래 예시는 + + ApplicationEngine.Configuration + + 클래스로 표현되는 사용자 정의 설정을 사용하여 여러 커넥터 엔드포인트로 서버를 실행하는 방법을 보여줍니다. +
++ 전체 예시는 + + embedded-server-multiple-connectors + 를 참고하세요. +
++ 사용자 정의 환경을 사용하여 + + HTTPS를 제공 + 할 수도 있습니다. +
+
+ Ktor를 사용하면 명령줄 인수를 사용하여 embeddedServer를 동적으로 설정할 수 있습니다. 이는 포트, 호스트 또는 타임아웃과 같은 설정을 런타임에 지정해야 하는 경우에 특히 유용할 수 있습니다.
+
+ 이를 위해 + + CommandLineConfig + + 클래스를 사용하여 명령줄 인수를 설정 객체로 파싱하고 설정 블록 내에서 전달합니다. +
+
+ 이 예시에서는 port 및 host와 같은 엔진 설정 값을 재정의하기 위해 Application.Configuration의
+
+ takeFrom()
+
+ 함수를 사용합니다.
+
+ loadCommonConfiguration()
+
+ 함수는 타임아웃과 같은 루트 환경의 설정을 로드합니다.
+
+ 서버를 실행하려면 다음과 같은 방식으로 인수를 지정합니다. +
++ 코드 예제: + + %example_name% + +
++ 이 튜토리얼에서는 첫 번째 Ktor 서버 프로젝트를 생성하고, 열고, 실행하는 방법을 배웁니다. 프로젝트가 실행되면 일련의 과제를 완료하여 Ktor에 익숙해질 수 있습니다. +
++ 이것은 Ktor로 서버 애플리케이션을 구축하기 위한 시작 단계인 일련의 튜토리얼 중 첫 번째입니다. 각 튜토리얼을 독립적으로 진행할 수 있지만, 다음 권장 순서를 따르는 것이 좋습니다: +
++ 새로운 Ktor 프로젝트를 생성하는 가장 빠른 방법 중 하나는 웹 기반 Ktor 프로젝트 생성기를 사용하는 것입니다. +
++ 또는 IntelliJ IDEA Ultimate용 전용 Ktor 플러그인이나 Ktor CLI 도구를 사용하여 프로젝트를 생성할 수 있습니다. +
++ Ktor 프로젝트 생성기로 새로운 프로젝트를 생성하려면 아래 단계를 따르세요: +
+Ktor 프로젝트 생성기로 이동합니다.
+
+
+
+
+
+ 다음 설정을 사용할 수 있습니다: +
+
+
+
+
이 튜토리얼에서는 이러한 설정에 대해 기본값을 그대로 두어도 됩니다.
+
+
아래에서 프로젝트에 추가할 수 있는
이 튜토리얼의 목적상, 지금 단계에서는 플러그인을 추가할 필요가 없습니다.
+
+
+
다운로드가 자동으로 시작됩니다.
+이제 새로운 프로젝트를 생성했으므로, 이어서 Ktor 프로젝트를 압축 해제하고 실행해 보겠습니다.
++ 이 섹션에서는 IntelliJ IDEA Ultimate용 Ktor 플러그인을 사용하여 프로젝트를 설정하는 방법을 설명합니다. +
++ 새로운 Ktor 프로젝트를 생성하려면 IntelliJ IDEA를 열고 다음 단계를 따르세요: +
+
+ 시작(Welcome) 화면에서
+ 또는 메인 메뉴에서
+
+ 오른쪽 창에서 다음 설정을 지정할 수 있습니다: +
+
+
+
+
+
+
+
+
+
+ + 다음 설정을 사용할 수 있습니다: +
+
+
+
+
이 튜토리얼의 목적상, 이러한 설정의 기본값을 그대로 두어도 됩니다.
+
+
+
+ 이 페이지에서 Ktor 애플리케이션의 공통 기능(예: 인증, 직렬화 및 콘텐츠 인코딩, 압축, 쿠키 지원 등)을 제공하는 구성 블록인
이 튜토리얼의 목적상, 지금 단계에서는 플러그인을 추가할 필요가 없습니다.
+
+
+ 이제 새로운 프로젝트를 생성했으므로, 이어서 애플리케이션을 열고, 탐색하고, 실행하는 방법을 알아봅니다. +
++ 이 섹션에서는 Ktor CLI 도구를 사용하여 프로젝트를 설정하는 방법을 설명합니다. +
++ 새로운 Ktor 프로젝트를 생성하려면 원하는 터미널을 열고 다음 단계를 따르세요: +
+
+
+ (선택 사항) 프로젝트 이름 아래의
+ 이 튜토리얼의 목적상, 지금 단계에서는 플러그인을 추가할 필요가 없습니다.
+
+ 또는
+ 이 섹션에서는 명령줄에서 프로젝트를 압축 해제하고, 빌드하고, 실행하는 방법을 알아봅니다. 아래 단계는 다음을 가정합니다: +
+필요한 경우 자신의 환경에 맞게 이름과 경로를 변경하세요.
+원하는 명령줄 도구를 열고 다음 단계를 따르세요:
+터미널 창에서 프로젝트를 다운로드한 폴더로 이동합니다:
+동일한 이름의 폴더에 ZIP 아카이브를 압축 해제합니다:
+이제 디렉토리에 ZIP 아카이브와 압축이 해제된 폴더가 포함됩니다.
+해당 디렉토리에서 새로 생성된 폴더로 이동합니다:
+macOS 및 UNIX 시스템에서는 Gradle 헬퍼 스크립트를 실행 가능하게 만들어야 시스템이 이를 실행 가능한 명령으로 인식합니다. 이를 위해 chmod 명령을 사용합니다:
프로젝트를 빌드하려면 다음 명령을 사용합니다:
+빌드가 성공하면 다음 단계로 넘어가 프로젝트를 실행합니다.
+프로젝트를 실행하려면 다음 명령을 사용합니다:
+프로젝트가 실행 중인지 확인하려면 터미널 출력에 표시된 URL(http://0.0.0.0:8080)로 브라우저를 엽니다. 브라우저에 "Hello World!" 메시지가 표시되어야 합니다:
+
+ 축하합니다! Ktor 프로젝트를 성공적으로 시작했습니다.
+IntelliJ IDEA가 설치되어 있다면 명령줄에서 쉽게 프로젝트를 열 수 있습니다.
+
+ 프로젝트 폴더에 있는지 확인한 다음, idea 명령 뒤에 현재 폴더를 나타내는 마침표를 입력합니다:
+
+ 또는 수동으로 프로젝트를 열려면 IntelliJ IDEA를 실행합니다. +
+
+ 시작(Welcome) 화면이 나타나면
프로젝트를 열면 다음과 같은 구조를 볼 수 있습니다:
+
+
+ 전체 레이아웃을 보려면
+ 애플리케이션 소스 코드는
+ 프로젝트 이름은
+ 구성 파일 및 기타 콘텐츠 종류는
+ IntelliJ IDEA 내에서 프로젝트를 실행하려면:
+오른쪽 사이드바의 Gradle 아이콘()을 클릭하여 Gradle 도구 창을 엽니다.
이 도구 창에서
+ Ktor 애플리케이션이 IDE 하단의 Run 도구 창에서 시작됩니다:
+
+ 이전에 명령줄에 표시되었던 것과 동일한 메시지가 이제
프로젝트가 실행 중인지 확인하려면 지정된 URL(http://0.0.0.0:8080)로 브라우저를 엽니다.
+화면에 다시 한 번 "Hello World!" 메시지가 표시되어야 합니다:
+
+
+
+ 이러한 옵션에 대한 자세한 설명은 IntelliJ IDEA Run 도구 창 문서를 참조하세요. +
+다음은 시도해 볼 수 있는 몇 가지 추가 과제입니다:
++ 이 과제들은 서로 종속되어 있지는 않지만 난이도가 점차 높아집니다. 선언된 순서대로 시도하는 것이 단계적으로 학습하기 가장 쉬운 방법입니다. 단순화하고 중복을 피하기 위해 아래 설명은 과제를 순서대로 시도하는 것을 가정합니다. +
++ 코딩이 필요한 경우 코드와 해당 import를 모두 지정했습니다. IDE가 이러한 import를 자동으로 추가해 줄 수도 있습니다. +
+
+ 구성을 YAML 또는 HOCON 파일 내에 외부적으로 저장하도록 선택한 경우,
port 값을 9292와 같이 원하는 다른 숫자로 변경합니다.
+ 재실행 버튼()을 클릭하여 애플리케이션을 재시작합니다.
애플리케이션이 새로운 포트 번호에서 실행 중인지 확인하려면 새로운 URL(http://0.0.0.0:9292)로 브라우저를 열거나, IntelliJ IDEA에서 새로운 HTTP Request 파일을 생성할 수 있습니다:
+
+ + 새로운 Ktor 프로젝트를 생성할 때, 구성을 코드에 저장하거나 YAML 또는 HOCON 파일 내에 외부적으로 저장하는 옵션이 있습니다. +
+
+ 구성을 코드에 저장하도록 선택한 경우,
embeddedServer() 함수에서 port 매개변수를 9292와 같이 원하는 다른 숫자로 변경합니다.
재실행 버튼()을 클릭하여 애플리케이션을 재시작합니다.
애플리케이션이 새로운 포트 번호에서 실행 중인지 확인하려면 새로운 URL(http://0.0.0.0:9292)로 브라우저를 열거나, IntelliJ IDEA에서 새로운 HTTP Request 파일을 생성할 수 있습니다:
+
+
+
새로운 엔드포인트를 생성하려면 아래와 같이 추가 라우트를 삽입합니다:
+/test1 URL은 원하는 대로 변경할 수 있습니다.IDE가 자동으로 ContentType에 대한 import를 추가합니다:
재실행 버튼()을 클릭하여 애플리케이션을 재시작합니다.
브라우저에서 새로운 URL(http://0.0.0.0:9292/test1)을 요청합니다. 포트 번호는 기본 포트 변경 과제를 완료했는지 여부에 따라 달라집니다. 아래와 같은 출력이 표시되어야 합니다:
+
+ HTTP request 파일을 생성했다면 거기에서도 새로운 엔드포인트를 확인할 수 있습니다:
+###)가 포함된 줄이 필요합니다.
+
이 줄의 의미는 다음과 같습니다:
+staticResources()를 호출하면 애플리케이션에서 HTML 및 JavaScript 파일과 같은 표준 웹사이트 콘텐츠를 제공할 수 있게 됩니다. 이 콘텐츠는 브라우저 내에서 실행될 수 있지만, 서버의 관점에서는 정적(static)인 것으로 간주됩니다.
+ /content는 이 콘텐츠를 가져오는 데 사용되는 경로를 지정합니다.
+ mycontent는 정적 콘텐츠가 위치할 폴더의 이름입니다. Ktor는 resources 디렉토리 내에서 이 폴더를 찾습니다.
+ IDE가 자동으로 추가하지 않는 경우 다음 import를 추가합니다.
+또는
새 디렉토리 이름을 mycontent로 지정하고
새로 생성된 폴더를 마우스 오른쪽 버튼으로 클릭하고
새 파일 이름을
새로 생성된 파일 페이지를 유효한 HTML로 채웁니다. 예:
+재실행 버튼()을 클릭하여 애플리케이션을 재시작합니다.
브라우저에서 http://0.0.0.0:9292/content/sample.html을 열면 샘플 페이지의 콘텐츠가 표시되어야 합니다:
+
+
+ Ktor는
이를 사용하려면 아래 단계를 따르세요:
+
+
testApplication() 함수는 Ktor의 새로운 인스턴스를 생성합니다. 이 인스턴스는 Netty와 같은 서버가 아닌 테스트 환경 내부에서 실행됩니다.
그런 다음 configure() 함수를 사용하여 embeddedServer()에서 호출되는 것과 동일한 설정을 호출할 수 있습니다.
마지막으로 내장된 client 객체와 JUnit assertion을 사용하여 샘플 요청을 보내고 응답을 확인할 수 있습니다.
+ IntelliJ IDEA에서 테스트를 실행하는 일반적인 방법 중 하나를 사용하여 테스트를 실행할 수 있습니다. Ktor의 새로운 인스턴스를 실행하는 것이므로 테스트의 성공 또는 실패는 애플리케이션이 0.0.0.0에서 실행 중인지 여부에 의존하지 않습니다.
+
+ 새로운 HTTP 엔드포인트 추가 과제를 성공적으로 완료했다면 다음 테스트를 추가해 보세요: +
+다음 추가 import를 추가합니다:
+
+
+ 다음 단계에서는 플러그인을 수동으로 추가하고 구성하는 방법을 배웁니다. 이를 달성하기 위한 네 가지 단계가 있습니다: +
+.configureRouting() 메서드로 이동하여 다음 코드 줄을 추가합니다:
이 줄들은 StatusPages 플러그인을 설치하고 IllegalStateException 유형의 예외가 발생했을 때 수행할 작업을 지정합니다.
다음 import를 추가합니다:
++ 일반적으로 응답에 HTTP 오류 코드가 설정되지만, 이 과제의 목적을 위해 출력이 브라우저에 직접 표시되도록 했습니다. +
+.configureRouting() 메서드 내에서 아래와 같이 추가 라우트를 추가합니다:
이제 URL이 /error-test인 엔드포인트를 추가했습니다. 이 엔드포인트가 트리거되면 핸들러에서 사용된 유형의 예외가 발생합니다.
재실행 버튼()을 클릭하여 애플리케이션을 재시작합니다.
브라우저에서 http://0.0.0.0:9292/error-test URL로 이동합니다. 아래와 같이 오류 메시지가 표시되어야 합니다:
+
+ + 추가 과제의 끝까지 마쳤다면 이제 Ktor 서버 구성, Ktor 플러그인 통합 및 새로운 라우트 구현에 대한 이해를 갖추게 된 것입니다. 하지만 이것은 시작에 불과합니다. Ktor의 기본 개념을 더 깊이 탐구하려면 이 가이드의 다음 튜토리얼로 계속 진행하세요. +
+
+ 다음으로는
+ 코드 예제: + embedded-server, + engine-main, + engine-main-yaml +
+
+ Ktor 애플리케이션을 생성하기 전에, 애플리케이션을 어떻게
+
+
+ 이 경우, 네트워크 요청을 처리하는 데 사용되는 애플리케이션
+
+ 이 경우, Ktor 애플리케이션은 애플리케이션 생명주기와 연결 설정을 제어하는 서블릿 컨테이너(Tomcat 또는 Jetty 등) 내부에서 배포될 수 있습니다. +
+
+ Ktor 서버 애플리케이션을 독립형 패키지로 제공하려면 먼저 서버를 생성해야 합니다.
+ 서버 설정에는 서버
+ embeddedServer 함수는
+
+ 코드에서 서버 파라미터를 설정
+
+ 하고 애플리케이션을 빠르게 실행할 수 있는 간단한 방법입니다.
+
+ EngineMain은 서버 설정을 위한 더 많은 유연성을 제공합니다.
+
+ 파일에 서버 파라미터를 지정
+
+ 할 수 있으며 애플리케이션을 다시 컴파일하지 않고도 설정을 변경할 수 있습니다.
+ 또한, 명령줄(command line)에서 애플리케이션을 실행하고 해당 명령줄 인수를 전달하여 필요한 서버 파라미터를 재정의(override)할 수 있습니다.
+
+ embeddedServer 함수는
+ Netty 엔진을 사용하여 서버를 실행하고 8080 포트에서 수신 대기합니다:
+
+ 전체 예제는 + + embedded-server + + 를 참조하세요. +
+
+ EngineMain은 선택한 엔진으로 서버를 시작하고 외부
+ 로드할 모듈을 지정하는 것 외에도, 설정 파일에는 포트, 호스트, SSL 설정과 같은 다양한 서버 파라미터를 포함할 수 있습니다. 예를 들어, 아래 설정은 서버 포트를 8080으로 설정합니다.
+
EngineMain.main()으로 서버를 즉시 시작하는 대신, EngineMain.createServer()를 사용하여 서버 인스턴스를 수동으로 생성할 수 있습니다. 자세한 내용은 를 참조하세요.
+ + 전체 예제는 + + engine-main + + 및 + + engine-main-yaml + + 을 참조하세요. +
+
+ Ktor 애플리케이션은 Tomcat 및 Jetty를 포함한 서블릿 컨테이너 내부에서 실행 및 배포될 수 있습니다.
+ 서블릿 컨테이너 내부에 배포하려면
+
+ 코드 예제: + + %example_name% + +
+
+ 사용된 플러그인:
+ 이 튜토리얼에서는 JSON 파일을 생성하는 RESTful API 예제를 통해 Kotlin과 Ktor를 사용하여 백엔드 서비스를 구축하는 방법을 설명합니다. +
+
+
+ 다음 내용을 배우게 됩니다: +
+이 튜토리얼은 독립적으로 진행할 수 있지만,
IntelliJ IDEA를 설치할 것을 권장하지만, 원하는 다른 IDE를 사용할 수도 있습니다. +
+이 튜토리얼에서는 기존의 Task Manager(작업 관리자)를 RESTful 서비스로 다시 작성해 보겠습니다. 이를 위해 여러 Ktor
+ 기존 프로젝트에 수동으로 추가할 수도 있지만, 새 프로젝트를 생성한 다음 이전 튜토리얼의 코드를 점진적으로 추가하는 것이 더 간단합니다. 진행하면서 모든 코드를 다시 반복할 것이므로 이전 프로젝트를 가지고 있을 필요는 없습니다. +
++ Ktor Project Generator로 이동합니다. +
+
+
+ Plugins 섹션에서
+
+ 플러그인을 추가하면 프로젝트 설정 아래에 모든 플러그인이 나열되는 것을 볼 수 있습니다.
+
+
+
IntelliJ IDEA에서 Ktor 프로젝트 열기, 탐색 및 실행 튜토리얼에서 설명한 대로 IntelliJ IDEA에서 프로젝트를 엽니다.
+
+
+
+ enum과 작업을 나타내는 class를 추가합니다:
+
+ 이전 튜토리얼에서는 확장 함수를 사용하여 Task를 HTML로 변환했습니다. 이번에는 Task 클래스에 kotlinx.serialization 라이브러리의 Serializable 타입 어노테이션이 추가되었습니다.
+
+
+ 이전 튜토리얼과 마찬가지로 URL /tasks에 대한 GET 요청 라우트를 만들었습니다. 이번에는 작업 목록을 수동으로 변환하는 대신 목록 자체를 반환하고 있습니다.
+
IntelliJ IDEA에서 실행 버튼()을 클릭하여 애플리케이션을 시작합니다.
+ 브라우저에서 http://0.0.0.0:8080/tasks로 이동합니다. 아래와 같이 JSON 형식의 작업 목록을 볼 수 있습니다: +
+
+ 상당히 많은 작업이 우리 대신 수행되고 있습니다. 정확히 무슨 일이 일어나고 있는 걸까요?
+
+ 프로젝트를 생성할 때
+ HTTP에서 클라이언트는 Accept 헤더를 통해 자신이 렌더링할 수 있는 콘텐츠 유형을 알립니다. 이 헤더의 값은 하나 이상의 콘텐츠 유형입니다. 위의 경우 브라우저에 내장된 개발자 도구를 사용하여 이 헤더의 값을 확인할 수 있습니다.
+
+ 다음 예시를 살펴보세요: +
+*/*가 포함되어 있음에 유의하세요. 이 헤더는 HTML, XML 또는 이미지를 허용하지만, 그 외의 다른 모든 콘텐츠 유형도 허용하겠다는 신호입니다.
Content Negotiation 플러그인은 브라우저에 데이터를 다시 보낼 형식을 찾아야 합니다. 프로젝트의 생성된 코드 내부를 보면
+ 이 코드는 ContentNegotiation 플러그인을 설치하고 kotlinx.serialization 플러그인을 구성합니다. 이렇게 하면 클라이언트가 요청을 보낼 때 서버가 JSON으로 직렬화된 객체를 다시 보낼 수 있습니다.
+
+ 브라우저의 요청의 경우, ContentNegotiation 플러그인은 JSON만 반환할 수 있다는 것을 알고 있고, 브라우저는 수신된 모든 것을 표시하려고 시도합니다. 따라서 요청이 성공합니다.
+
+ 프로덕션 환경에서는 일반적으로 JSON을 브라우저에 직접 표시하지 않습니다. 대신 브라우저에서 실행되는 JavaScript 코드가 요청을 수행한 다음 반환된 데이터를 SPA(Single Page Application)의 일부로 표시합니다. 일반적으로 이러한 종류의 애플리케이션은 React, Angular 또는 Vue.js와 같은 프레임워크를 사용하여 작성됩니다. +
+
+ 이를 시뮬레이션하기 위해
+ 이 페이지는 HTML 폼과 빈 테이블을 포함하고 있습니다. 폼을 제출하면 JavaScript 이벤트 핸들러가 Accept 헤더를 application/json으로 설정하여 /tasks 엔드포인트로 요청을 보냅니다. 반환된 데이터는 역직렬화되어 HTML 테이블에 추가됩니다.
+
+ IntelliJ IDEA에서 재실행 버튼()을 클릭하여 애플리케이션을 다시 시작합니다.
+
+ URL http://0.0.0.0:8080/static/index.html로 이동합니다.
+
+ 이제 콘텐츠 협상 프로세스에 익숙해졌으니,
+ 작업 레포지토리는 수정 없이 재사용할 수 있으므로, 이를 먼저 수행하겠습니다. +
+
+
+
+ 레포지토리를 만들었으므로 GET 요청을 위한 라우트를 구현할 수 있습니다. 작업을 HTML로 변환하는 것을 더 이상 걱정할 필요가 없으므로 이전 코드를 단순화할 수 있습니다: +
+
+
+ Application.configureRouting() 함수 내부의 /tasks 라우트 코드를 다음 구현으로 업데이트합니다:
+
+ 이제 서버는 다음과 같은 GET 요청에 응답할 수 있습니다:
+/tasks는 레포지토리의 모든 작업을 반환합니다./tasks/byName/{taskName}은 지정된 taskName으로 필터링된 작업을 반환합니다./tasks/byPriority/{priority}는 지정된 priority로 필터링된 작업들을 반환합니다.
+ IntelliJ IDEA에서 재실행 버튼()을 클릭하여 애플리케이션을 다시 시작합니다.
+
브라우저에서 이러한 라우트를 테스트할 수 있습니다. 예를 들어, http://0.0.0.0:8080/tasks/byPriority/Medium으로 이동하면 Medium 우선순위를 가진 모든 작업이 JSON 형식으로 표시되는 것을 볼 수 있습니다:
+ + 이러한 요청은 일반적으로 JavaScript에서 오기 때문에 더 세밀한 테스트가 바람직합니다. 이를 위해 Postman과 같은 전문 도구를 사용할 수 있습니다. +
+Postman에서 URL이 http://0.0.0.0:8080/tasks/byPriority/Medium인 새 GET 요청을 만듭니다.
+ application/json으로 설정합니다.
+
+ IntelliJ IDEA Ultimate에서는 HTTP 요청 파일에서 동일한 단계를 수행할 수 있습니다.
+
+ 프로젝트 루트 디렉토리에 새
+
+ IntelliJ IDEA 내에서 요청을 보내려면 옆에 있는 거터 아이콘()을 클릭합니다.
+
이것은
+
+ 이전 튜토리얼에서는 HTML 폼을 통해 작업을 생성했습니다. 하지만 이제 RESTful 서비스를 구축하고 있으므로 더 이상 그렇게 할 필요가 없습니다. 대신 대부분의 번거로운 작업을 대신 해줄 kotlinx.serialization 프레임워크를 활용할 것입니다.
+
+
+ 다음과 같이 Application.configureRouting() 함수에 새 POST 라우트를 추가합니다:
+
+ 다음의 새 import 문들을 추가합니다: +
+
+ POST 요청이 /tasks로 전송되면, kotlinx.serialization 프레임워크가 요청 본문을 Task 객체로 변환하는 데 사용됩니다. 성공하면 작업이 레포지토리에 추가됩니다. 역직렬화 프로세스가 실패하면 서버는 SerializationException을 처리하고, 작업이 중복된 경우 IllegalStateException을 처리합니다.
+
+ 애플리케이션을 다시 시작합니다. +
+
+ Postman에서 이 기능을 테스트하려면 URL http://0.0.0.0:8080/tasks로 새 POST 요청을 만듭니다.
+
+
+ + http://0.0.0.0:8080/tasks로 GET 요청을 보내 작업이 추가되었는지 확인할 수 있습니다. +
++ IntelliJ IDEA Ultimate 내에서 HTTP 요청 파일에 다음 내용을 추가하여 동일한 단계를 수행할 수 있습니다: +
++ 서비스에 기본 작업들을 거의 다 추가했습니다. 이러한 작업들은 종종 CRUD(Create, Read, Update, and Delete) 작업으로 요약됩니다. 이제 삭제(Delete) 작업을 구현하겠습니다. +
+
+ TaskRepository 객체 내에 이름을 기반으로 작업을 제거하는 다음 메서드를 추가합니다:
+
+ routing() 함수에 추가합니다:
+
+ 애플리케이션을 다시 시작합니다. +
++ HTTP 요청 파일에 다음 DELETE 요청을 추가합니다: +
+
+ IntelliJ IDEA 내에서 DELETE 요청을 보내려면 옆에 있는 거터 아이콘()을 클릭합니다.
+
+
+ 지금까지는 애플리케이션을 수동으로 테스트했지만, 이미 눈치채셨겠지만 이 방식은 시간이 많이 걸리고 규모를 확장하기 어렵습니다. 대신 내장된 client 객체를 사용하여 JSON을 가져오고 역직렬화하는
+
+
+ 서버에서 했던 것과 동일한 방식으로 Plugins에 ContentNegotiation 및 kotlinx.serialization 플러그인을 설치해야 함에 유의하세요.
+
+
+ Ktor 클라이언트나 유사한 라이브러리로 서비스를 테스트하는 것은 편리하지만, 품질 보증(QA) 관점에서는 단점이 있습니다. JSON을 직접 처리하지 않는 서버는 JSON 구조에 대한 가정이 확실하다고 확신할 수 없습니다. +
++ 예를 들어 다음과 같은 가정들입니다: +
+object가 사용되는데 값이 array에 저장되고 있다고 가정하는 경우.strings인데 numbers로 저장되고 있다고 가정하는 경우.+ 서비스를 여러 클라이언트가 사용할 예정이라면 JSON 구조에 대한 확신을 갖는 것이 중요합니다. 이를 위해 Ktor Client를 사용하여 서버에서 텍스트를 가져온 다음 JSONPath 라이브러리를 사용하여 이 콘텐츠를 분석합니다.
+dependencies 블록에 JSONPath 라이브러리를 추가합니다:
+
+
+
+ JsonPath 쿼리는 다음과 같이 작동합니다: +
+$[*].name은 "문서를 배열로 처리하고 각 항목의 name 속성 값을 반환하라"는 의미입니다.
+ $[?(@.priority == '$priority')].name은 "우선순위가 제공된 값과 동일한 배열의 모든 항목에 대해 name 속성 값을 반환하라"는 의미입니다.
+ + 이와 같은 쿼리를 사용하여 반환된 JSON에 대한 이해가 올바른지 확인할 수 있습니다. 코드 리팩토링이나 서비스 재배포를 수행할 때, 현재 프레임워크에서의 역직렬화에 문제가 없더라도 직렬화 과정에서의 모든 변경 사항을 식별할 수 있습니다. 이를 통해 공개적으로 사용 가능한 API를 자신 있게 다시 배포할 수 있습니다. +
++ 축하합니다! 이제 Task Manager 애플리케이션을 위한 RESTful API 서비스를 성공적으로 완성했으며, Ktor Client와 JsonPath를 사용한 유닛 테스트의 세부 사항을 배웠습니다.
+
+
+ 코드 예제: + + %example_name% + +
+
+ 사용된 플러그인:
+ 이 튜토리얼에서는 Kotlin과 타임리프(Thymeleaf) 템플릿을 사용하여 Ktor로 상호작용 가능한 웹사이트를 구축하는 방법을 배웁니다. +
+
+
+ 다음과 같이 모든 구현을 서버에 유지하고 클라이언트에는 마크업만 보내고 싶을 때가 많습니다: +
+
+ Ktor는
+ 이 튜토리얼은 독립적으로 진행할 수 있지만, RESTful API 생성 방법을 배우기 위해
IntelliJ IDEA를 설치하는 것을 권장하지만, 원하는 다른 IDE를 사용해도 무방합니다. +
+
+ 이 튜토리얼에서는
+ 기존 프로젝트에 이러한 플러그인을 수동으로 추가할 수도 있지만, 새 프로젝트를 생성하고 이전 튜토리얼의 코드를 점진적으로 통합하는 것이 더 쉽습니다. 필요한 모든 코드를 과정 중에 제공하므로 이전 프로젝트를 따로 준비해 둘 필요는 없습니다. +
++ Ktor Project Generator로 이동합니다. +
+
+
+
다음 화면에서
+
+ 플러그인을 추가하면 프로젝트 설정 아래에 세 개의 플러그인이 모두 표시됩니다.
+
+
+
+ enum과 할 일을 나타내는 data class를 추가합니다:
+
+ 다시 한번 말씀드리지만, Task 객체를 생성하여 클라이언트가 표시할 수 있는 형식으로 전달하고자 합니다.
+
+ 다음 내용을 기억하실 것입니다: +
+kotlinx.serialization 라이브러리의 Serializable 타입을 Task 클래스에 어노테이션으로 추가했습니다.
+ + 이번 경우에는 할 일의 내용을 브라우저에 출력하는 서버 페이지를 만드는 것이 목표입니다. +
+
+ .configureRouting() 함수에 아래와 같이 /tasks 라우트를 추가합니다:
+
+ 서버가 /tasks에 대한 요청을 받으면 할 일 목록을 생성한 다음 타임리프 템플릿으로 전달합니다. ThymeleafContent 타입은 트리거할 템플릿 이름과 페이지에서 접근할 수 있는 값들의 테이블을 인자로 받습니다.
+
다음과 같은 .configureThymeleaf 함수를 볼 수 있습니다:
+ 타임리프 플러그인 초기화 시, Ktor는 서버 페이지를 찾기 위해
+
+ 이 경우, all-tasks라는 이름은 다음 경로와 매핑됩니다:
+ src/main/resources/templates/thymeleaf/all-tasks.html
+
+
IntelliJ IDEA에서 실행 버튼
+ ()
+ 을 클릭하여 애플리케이션을 시작합니다.
+ 브라우저에서 http://0.0.0.0:8080/tasks로 이동합니다. 아래와 같이 표에 모든 현재 할 일이 표시되는 것을 확인할 수 있습니다: +
+
+ + 모든 서버 페이지 프레임워크와 마찬가지로, 타임리프 템플릿은 정적 콘텐츠(브라우저로 전송됨)와 동적 콘텐츠(서버에서 실행됨)를 혼합하여 사용합니다. 만약 Freemarker와 같은 다른 프레임워크를 선택했더라도 약간 다른 구문으로 동일한 기능을 구현할 수 있었을 것입니다. +
+이제 서버 페이지를 요청하는 과정에 익숙해졌으므로, 이전 튜토리얼의 기능을 이 프로젝트로 계속 옮겨보겠습니다.
+
+
+ 이는 예를 들어 /static/index.html에 대한 요청이 다음 경로의 콘텐츠를 제공함을 의미합니다:
+
src/main/resources/static/index.html
+ + 이 파일은 생성된 프로젝트에 이미 포함되어 있으므로, 추가하려는 기능의 홈 페이지로 사용할 수 있습니다. +
+
+
+ IntelliJ IDEA에서 재실행 버튼()을 클릭하여 애플리케이션을 다시 시작합니다.
+
+ 브라우저에서 http://localhost:8080/static/index.html로 이동합니다. 할 일을 조회, 필터링 및 생성할 수 있는 링크 버튼과 세 개의 HTML 폼이 표시되어야 합니다: +
+
+
+ name 또는 priority로 할 일을 필터링할 때 GET 요청을 통해 HTML 폼을 전송한다는 점에 유의하세요. 이는 매개변수가 URL 뒤의 쿼리 스트링(query string)에 추가됨을 의미합니다.
+
+ 예를 들어 Medium 우선순위의 할 일을 검색하면 서버로 전송되는 요청은 다음과 같습니다:
+
http://localhost:8080/tasks/byPriority?priority=Medium
+ + 할 일 저장소(repository)는 이전 튜토리얼과 동일하게 유지할 수 있습니다. +
+
+
+ 저장소를 만들었으므로 이제 GET 요청에 대한 라우트를 구현할 수 있습니다. +
+
+ 현재 버전의 .configureRouting()을 아래 구현으로 대체합니다:
+
+ 위 코드는 다음과 같이 요약할 수 있습니다: +
+/tasks에 대한 GET 요청 시, 서버는 저장소에서 모든 할 일을 가져와
+ /tasks/byName에 대한 GET 요청 시, 서버는 queryString에서 name 매개변수를 가져와 일치하는 할 일을 찾고,
+ /tasks/byPriority에 대한 GET 요청 시, 서버는 queryString에서 priority 매개변수를 가져와 일치하는 할 일들을 찾고,
+ 이 모든 것이 작동하려면 추가 템플릿을 추가해야 합니다.
+
+
동일한 폴더에
+
+
+ 다음으로, /tasks에 POST 요청 핸들러를 추가하여 다음 작업을 수행하겠습니다:
+
+ .configureRouting() 메서드 내에 다음 post 요청 라우트를 추가합니다:
+
+ IntelliJ IDEA에서 재실행 버튼()을 클릭하여 애플리케이션을 다시 시작합니다.
+
+
+
+ + 축하합니다! 할 일 관리자(Task Manager)를 웹 애플리케이션으로 다시 빌드하고 타임리프 템플릿 사용법을 배웠습니다.
+
+
+ 코드 예제: + + %example_name% + +
+
+ 사용된 플러그인:
+ 이 문서는 Ktor와 Kotlin을 사용하여 WebSocket 애플리케이션을 제작하는 과정을 안내합니다. 이 내용은
이 문서에서는 다음 내용을 학습하게 됩니다:
+이 튜토리얼을 독립적으로 진행할 수 있지만,
IntelliJ IDEA를 설치하는 것을 권장하지만, 원하는 다른 IDE를 사용해도 좋습니다. +
+
+ 이 튜토리얼에서는 WebSocket 연결을 통해 클라이언트와 Task 객체를 주고받는 기능을 추가하여
+ Ktor Project Generator로 이동합니다. +
+
+
+ 플러그인 섹션에서
+
+
+ 플러그인을 추가하면 플러그인 섹션의 오른쪽 상단에 표시됩니다. +
+프로젝트에 추가될 모든 플러그인 목록을 확인할 수 있습니다:
+
+
+
다운로드가 완료되면 IntelliJ IDEA에서 프로젝트를 열고 다음 단계를 따르세요:
+
+
+ enum과 작업을 나타내는 data class를 추가합니다:
+
+ Task 클래스는 kotlinx.serialization 라이브러리의 @Serializable 어노테이션이 붙어 있습니다. 이는 인스턴스를 JSON으로 상호 변환할 수 있음을 의미하며, 이를 통해 네트워크를 통해 내용을 전송할 수 있습니다.
+
+ WebSockets 플러그인을 포함했으므로 제너레이터가 webSocket 라우트를, 그리고
.configureWebsockets() 함수를 다음 내용으로 교체합니다:
+ contentConverter 속성이 설정되어, 플러그인이 kotlinx.serialization 라이브러리를 통해 송수신되는 객체를 직렬화할 수 있게 합니다.
+
+ Application.configureRouting() 함수를 아래 구현으로 교체합니다:
+
/tasks인 단일 엔드포인트로 라우팅이 구성됩니다.
+ 데모를 위해 작업을 전송하는 사이에 1초의 지연(delay)을 추가했습니다. 이를 통해 클라이언트에서 작업이 점진적으로 나타나는 것을 관찰할 수 있습니다. 이 지연이 없다면 이 예제는 이전 문서에서 개발한
+ 이 반복 단계의 마지막 과정은 이 엔드포인트를 위한 클라이언트를 만드는 것입니다.
+
+ 이 페이지는 모든 최신 브라우저에서 사용할 수 있는 WebSocket 유형을 사용합니다. JavaScript에서 이 객체를 생성하고 생성자에 엔드포인트의 URL을 전달합니다. 그 후 onopen, onclose, onmessage 이벤트에 대한 이벤트 핸들러를 연결합니다. onmessage 이벤트가 트리거되면 문서 객체의 메서드를 사용하여 테이블에 행을 추가합니다.
+
IntelliJ IDEA에서 실행 버튼
+ ()을 클릭하여 애플리케이션을 시작합니다.
+ http://0.0.0.0:8080/static/index.html로 이동합니다. 버튼이 있는 폼과 빈 테이블이 나타날 것입니다: +
+
+
+ 폼을 클릭하면 서버에서 작업이 로드되어 초당 한 개씩 나타납니다. 결과적으로 테이블이 점진적으로 채워집니다. 브라우저의
+ + 이제 서비스가 예상대로 작동합니다. WebSocket 연결이 열리고, 항목이 클라이언트로 전송된 다음 연결이 닫힙니다. 기저의 네트워킹에는 많은 복잡성이 수반되지만, Ktor가 기본적으로 이 모든 것을 처리해 줍니다. +
++ 다음 단계로 넘어가기 전에 WebSockets의 기본 사항을 복습하는 것이 도움이 될 수 있습니다. 이미 WebSockets에 익숙하다면 바로 서비스 설계 개선 단계로 넘어가도 좋습니다. +
++ 이전 튜토리얼에서 클라이언트는 HTTP 요청을 보내고 HTTP 응답을 받았습니다. 이는 잘 작동하며 인터넷이 확장 가능하고 탄력적으로 유지될 수 있게 합니다. +
+그러나 다음과 같은 시나리오에는 적합하지 않습니다:
++ 이러한 시나리오의 예로는 주식 거래, 영화 및 콘서트 티켓 구매, 온라인 경매 입찰, 소셜 미디어의 채팅 기능 등이 있습니다. WebSockets는 이러한 상황을 처리하기 위해 개발되었습니다. +
+
+ WebSocket 연결은 TCP를 통해 구축되며 장기간 유지될 수 있습니다. 이 연결은
+ WebSocket API는 네 가지 이벤트(open, message, close, error)와 두 가지 동작(send, close)을 정의합니다. 이러한 기능에 접근하는 방법은 언어와 라이브러리에 따라 다를 수 있습니다. 예를 들어, Kotlin에서는 들어오는 메시지 시퀀스를 Flow로 소비할 수 있습니다.
+
다음으로, 더 고급 예제를 구현하기 위해 기존 코드를 리팩토링해 보겠습니다.
+
+
+ TaskRepository 객체를 추가합니다:
+
이 코드는 이전 튜토리얼에서 보았던 것과 비슷할 것입니다.
+
+ 이제 TaskRepository를 활용하여 Application.configureRouting()의 라우팅을 단순화할 수 있습니다:
+
+ WebSocket의 강력함을 보여주기 위해 다음과 같은 새 엔드포인트를 만들어 보겠습니다: +
+
+ .configureRouting() 메서드를 아래 구현으로 교체합니다:
+
이 코드를 통해 다음 작업을 수행했습니다:
+routing {} 블록에서 모든 클라이언트를 추적하기 위해 스레드로부터 안전한 session 객체 리스트를 생성했습니다.
+ /tasks2인 새 엔드포인트를 추가했습니다. 클라이언트가 이 엔드포인트에 연결하면 해당 session 객체가 리스트에 추가됩니다. 그런 다음 서버는 새 작업을 수신하기 위해 대기하는 무한 루프에 진입합니다. 새 작업을 수신하면 서버는 이를 저장소에 저장하고 현재 클라이언트를 포함한 모든 클라이언트에게 복사본을 보냅니다.
+
+ 이 기능을 테스트하기 위해
+
+
+ 이 새 페이지에는 사용자가 새 작업 정보를 입력할 수 있는 HTML 폼이 도입되었습니다. 폼을 제출하면 sendTaskToServer() 이벤트 핸들러가 호출됩니다. 이는 폼 데이터로 JavaScript 객체를 빌드하고 WebSocket 객체의 .send() 메서드를 사용하여 서버로 전송합니다.
+
+ IntelliJ IDEA에서 재실행 버튼()을 클릭하여 애플리케이션을 다시 시작합니다.
+
이 기능을 테스트하려면 두 개의 브라우저를 나란히 열고 다음 단계를 따르세요.
+
+
+ QA 프로세스를 효율화하고 빠르고 재현 가능하며 자동화하기 위해 Ktor의 내장된
+ Ktor Client 내에서
+
IntelliJ IDEA에서 편집기 오른쪽에 있는 Gradle 알림 아이콘
+ ()을 클릭하여 Gradle 변경 사항을 로드합니다.
+
+ 생성된 테스트 클래스를 아래 구현으로 교체합니다: +
++ 이 설정을 통해 다음을 수행합니다: +
+Tasks 목록을 선언합니다.
+ client 객체의 .webSocket 함수를 사용하여 /tasks로 요청을 보냅니다.
+ Flow로 소비하여 리스트에 점진적으로 추가합니다.
+ expectedTasks와 actualTasks를 비교합니다.
+ + 수고하셨습니다! WebSocket 통신과 Ktor Client를 사용한 자동화 테스트를 통합함으로써 작업 관리자 서비스를 크게 개선했습니다. +
+
+
+ 이 주제에서는 기존 Gradle/Maven 프로젝트에 Ktor 서버에 필요한 의존성을 추가하는 방법을 보여줍니다. +
++ Ktor 의존성을 추가하기 전에 이 프로젝트의 저장소를 구성해야 합니다. +
+
+
+ Ktor의 프로덕션 릴리스는 Maven 중앙 저장소(Maven central repository)에서 사용할 수 있습니다. + 다음과 같이 빌드 스크립트에 이 저장소를 선언할 수 있습니다. +
+
+ 프로젝트가 Super POM에서 중앙 저장소를 상속받으므로
+
+ Ktor의 EAP 버전에 접근하려면 Space 저장소를 참조해야 합니다. +
++ Ktor EAP에는 Kotlin 개발 저장소 (dev repository)가 필요할 수 있습니다. +
++ 모든 Ktor 애플리케이션에는 최소한 다음 의존성이 필요합니다. +
+
+ ktor-server-core: 핵심 Ktor 기능이 포함되어 있습니다.
+
+ ktor-server-netty).
+
+ 다양한 플랫폼을 위해 Ktor는 ktor-server-core-jvm 또는 ktor-server-netty-jvm과 같이 -jvm과 같은 접미사가 붙은 플랫폼별 아티팩트(artifact)를 제공합니다.
+ Gradle은 지정된 플랫폼에 적합한 아티팩트를 자동으로 확인하는 반면, Maven은 이 기능을 지원하지 않습니다.
+ 즉, Maven의 경우 플랫폼별 접미사를 수동으로 추가해야 합니다.
+ 기본 Ktor 애플리케이션의 dependencies 블록은 다음과 같을 수 있습니다.
+
+ Ktor는 다양한 로깅 프레임워크(예: Logback 또는 Log4j)의 퍼사드(facade)로 SLF4J API를 사용하며, 애플리케이션 이벤트를 로그로 남길 수 있게 해줍니다. + 필요한 아티팩트를 추가하는 방법을 알아보려면 로거 의존성 추가하기를 참조하세요. +
+
+ Ktor 기능을 확장하는
+ Ktor Gradle 플러그인을 적용하면 + Ktor BOM 의존성이 암시적으로 추가되어 모든 Ktor 의존성이 동일한 버전인지 확인할 수 있습니다. + 이 경우 Ktor 아티팩트에 의존할 때 더 이상 버전을 지정할 필요가 없습니다. +
++ 게시된 버전 카탈로그(version catalog)를 사용하여 Ktor 의존성 선언을 중앙 집중화할 수도 있습니다. + 이 접근 방식은 다음과 같은 이점을 제공합니다. +
+
+ 카탈로그를 선언하려면
+ 그런 다음 모듈의
+ Gradle/Maven을 사용하여 Ktor 서버를
+ embeddedServer를 사용하는 경우 다음과 같이 메인 클래스를 지정합니다. +
++ EngineMain을 사용하는 경우 이를 메인 클래스로 구성해야 합니다. + Netty의 경우 다음과 같습니다. +
++ 애플리케이션을 Fat JAR로 패키징하려는 경우, 해당 플러그인을 구성할 때 서버를 생성하는 방식도 고려해야 합니다. + 다음 주제에서 더 자세히 알아보세요. +
+
+
+
+ Ktor는 개발을 위해 특화된 특별한 모드를 제공합니다. 이 모드를 사용하면 다음과 같은 기능들을 활용할 수 있습니다. +
++ 개발 모드는 성능에 영향을 미치므로 운영 환경(production)에서는 사용해서는 안 됩니다. +
++ 애플리케이션 설정 파일, 전용 시스템 속성 또는 환경 변수를 사용하는 등 다양한 방법으로 개발 모드를 활성화할 수 있습니다. +
+
+ development 옵션을 true로 설정하세요.
+
+ io.ktor.development 시스템 속성을 사용하면 애플리케이션을 실행할 때 개발 모드를 활성화할 수 있습니다.
+
+ IntelliJ IDEA를 사용하여 애플리케이션을 개발 모드로 실행하려면, -D 플래그와 함께 io.ktor.development를 VM 옵션에 전달하세요.
+
+
+ build.gradle.kts 파일의 ktor 블록을 구성합니다.
+
+ Gradle CLI 플래그를 전달하여 단일 실행에 대해 개발 모드를 활성화합니다. +
+
+ -ea 플래그를 사용하여 개발 모드를 활성화할 수도 있습니다.
+ 단, -D 플래그로 전달된 io.ktor.development 시스템 속성이 -ea보다 우선순위를 가집니다.
+
+ 네이티브 클라이언트(Native client)의 개발 모드를 활성화하려면 io.ktor.development 환경 변수를 사용하세요.
+
+
+ Ktor 这个名字源于缩写 ctor(构造函数),并将第一个字母替换为代表 Kotlin 的 “K”。
+
+ 请访问 Support 页面以详细了解可用的支持渠道。 + How to contribute 指南介绍了您可以为 Ktor 做出贡献的方式。 +
+
+ CIO 代表
+
+ 请确保已在构建脚本中添加了相应的
+ 如果您正在运行 EngineMain,它将自动处理。
+ 否则,您需要手动处理。
+ 您可以使用 JVM 提供的 Runtime.getRuntime().addShutdownHook 设施。
+
+ 如果代理提供了正确的标头,并且安装了 call.request.origin 属性会提供有关原始调用者(代理)的连接信息。
+
+ 您可以从 jetbrains.space 获取 Ktor 每夜构建版本。
+ 详情请参阅 抢先体验计划。
+
+ 您可以使用 Server 响应标头,例如:
+
+ Ktor 提供了一种跟踪机制来帮助排查路由决策。 + 请查看 Tracing routes 章节。 +
+
+ 这意味着您、或者某个插件或拦截器已经调用过 call.respond* 函数,而您正试图再次调用它。
+
+ 请参阅
+ 这意味着 Ktor 无法找到 resources 文件夹中存在配置文件,并且该 resources 文件夹已被正确标记。
+ 可以考虑使用 Ktor 项目生成器 或 IntelliJ IDEA Ultimate 的 Ktor 插件 来创建一个可以运行的项目作为基础。有关更多信息,请参阅
+ 是的,已知 Ktor 服务器和客户端可以在 Android 5 (API 21) 或更高版本上运行,至少在使用 Netty 引擎时是这样。 +
+
+ CURL -I 是 CURL --head 的别名,执行的是 HEAD 请求。
+ 默认情况下,Ktor 不会为 GET 处理程序处理 HEAD 请求。
+ 要启用此功能,请安装
+ 最可能的原因是您的后端位于反向代理或负载均衡器之后,而这些中间件正在向您的后端发起普通的 HTTP 请求,因此 Ktor 后端中的 HttpsRedirect 插件认为这是一个普通的 HTTP 请求并响应重定向。
+
+ 通常,反向代理会发送一些描述原始请求的标头(例如它是否为 HTTPS,或原始 IP 地址),可以使用
+ Curl 客户端引擎需要安装 curl 库。
+ 在 Windows 上,您可以考虑使用 MinGW/MSYS2 的 curl 二进制文件。
+
+ 按照 MinGW/MSYS2 中的说明安装 MinGW/MSYS2。 +
+
+ 使用以下命令安装 libcurl:
+
+ 如果您将 MinGW/MSYS2 安装到了默认位置,请将
+ PATH 环境变量中。
+
+ NoTransformationFoundException + 表示无法为接收到的正文找到合适的转换,即无法将生成的(resulted)类型转换为客户端预期的(expected)类型。 +
+
+ 检查请求中的 Accept 标头是否指定了所需的内容类型,以及服务器响应中的 Content-Type 标头是否与客户端预期的类型匹配。
+
+ 为您正在处理的特定内容类型注册必要的内容转换。 +
++ 您可以在客户端使用 ContentNegotiation 插件。 + 此插件允许您指定如何针对不同的内容类型对数据进行序列化和反序列化。 +
++ 确保安装了所有需要的插件。可能缺失的功能包括: +
++ 代码示例: + + %example_name% + +
+
+ Ktor 包含一个多平台异步 HTTP 客户端,允许您
+ 在本教程中,我们将向您展示如何创建第一个发送请求并打印响应的 Ktor 客户端应用程序。 +
++ 在开始本教程之前,请安装 IntelliJ IDEA Community 或 Ultimate。 +
+
+ 您可以手动在现有项目中
+ 要创建一个新的 Kotlin 项目,请打开 IntelliJ IDEA 并按照以下步骤操作: +
+
+ 在欢迎界面中,点击
+ 或者,从主菜单中选择
+ 在
+
+ 在右侧窗格中,指定以下设置: +
+
+
+
+
+
+
+
+ 点击
+
+ 让我们添加 Ktor 客户端所需的依赖项。 +
+
+ 打开
+
+ 要使用 Ktor 的 EAP 版本,您需要添加 Space 仓库。 +
+
+ 打开
+
ktor-client-core 是提供主要客户端功能的核心依赖项。
+ ktor-client-cio 是处理网络请求的
+ 点击
+
+
+ 要添加客户端实现,请导航至
+
+ 打开
+
+ 在 Ktor 中,客户端由 HttpClient + 类表示。 +
+
+ 使用 HttpClient.get() 方法来HttpResponse 类对象接收。
+
+ 添加上述代码后,IDE 会对 get() 函数显示以下错误:
+
+
+ 要修复此错误,您需要使 main() 函数成为 suspending。
+
suspend 函数,请参阅协程基础知识。
+
+ 在 IntelliJ IDEA 中,点击定义旁边的灯泡图标并选择
+
+
+ 使用 println() 函数打印服务器返回的状态码,并使用 close() 函数关闭流并释放与其关联的所有资源。
+
+ 要运行您的应用程序,请导航至
+
+ 在 IntelliJ IDEA 中,点击 main() 函数旁边的装订区域图标,然后选择
+
+
+ 您将在 IDE 底部的
+
+
+ 虽然服务器返回了 200 OK 消息,但您还会看到一条错误消息,指出 SLF4J 无法定位
+ StaticLoggerBinder 类,默认使用无操作 (NOP) 日志记录器实现。这实际上意味着日志记录已被禁用。
+
+ 您现在已经拥有了一个可以运行的客户端应用程序。但是,要修复此警告并能够通过日志调试 HTTP 调用,还需要执行额外步骤。 +
++ 由于 Ktor 在 JVM 上使用 SLF4J 抽象层进行日志记录,要启用日志记录,您需要提供一个日志框架,例如 + Logback。 +
+
+ 在
+
+ 打开
+
+ 在 IntelliJ IDEA 中,点击重新运行按钮()以重启应用程序。
+
+ 您应该不再看到错误,但同样的 200 OK 消息仍将显示在 IDE 底部的
+
+ + 至此,您已启用了日志功能。要开始看到日志,您需要添加日志配置。 +
+导航至
+
+ 在 IntelliJ IDEA 中,点击重新运行按钮()以重启应用程序。
+
+ 您现在应该能够在
+
+
+ 要更好地理解并扩展此配置,请探索如何
+ 代码示例: + + %example_name% + +
++ Server-Sent Events (SSE) 是一项允许服务器通过 HTTP 连接持续向客户端推送事件的技术。它在服务器需要发送基于事件的更新而无需客户端反复轮询服务器的情况下特别有用。 +
++ Ktor 支持的 SSE 插件提供了一种在服务器和客户端之间创建单向连接的简便方法。 +
+要了解更多关于服务器端支持的 SSE 插件的信息,请参阅
+
+ SSE 仅需要
+ 要安装 SSE 插件,请在 客户端配置块 内将其传递给 install 函数:
+
+ 您可以选择在 install 块中通过设置 SSEConfig 类支持的属性来配置 SSE 插件。
+
+ 要启用自动重连,请将 maxReconnectionAttempts 设置为大于 0 的值。您还可以使用 reconnectionTime 配置尝试之间的延迟:
+
+ 如果与服务器的连接丢失,客户端将在尝试重连之前等待指定的 reconnectionTime。它将尝试最多 maxReconnectionAttempts 次来重新建立连接。
+
+ 在以下示例中,SSE 插件安装到 HTTP 客户端,并配置为在传入流中包含仅包含注释的事件以及仅包含 retry 字段的事件:
+
+ SSE 响应本质上是流式的,这使得捕获完整正文变得不切实际。您可以启用诊断缓冲区,以便在 SSE 流失败时安全地检索响应正文。缓冲区仅包含已处理的数据(不会从网络重新读取),旨在用于失败情况下的日志记录和错误分析。 +
++ 您还可以按调用配置缓冲区: +
+
+ SSEBufferPolicy 类型提供了几种存储已处理 SSE 数据的策略。这些策略控制内存中保留多少流数据,并在发生错误时使其可用。
+
Off(默认)LastLines(n)LastEventLastEvents(n)All
+ 失败时,您可以使用 response?.bodyAsText() 访问缓冲区,而无需从网络重新读取。
+
+ 客户端的 SSE 会话由 ClientSSESession 接口表示。该接口公开了允许您接收来自服务器的服务器发送事件的 API。
+
HttpClient 允许您通过以下方式之一访问 SSE 会话:
sse() 函数创建 SSE 会话并允许您对其执行操作。
+ sseSession() 函数允许您打开一个 SSE 会话。
+ 要指定 URL 端点,您可以从两个选项中进行选择:
+urlString 形参将整个 URL 指定为字符串。schema、host、port 和 path 形参来指定协议方案、域名、端口号和路径名。ClientSSESession 和 ClientSSESessionWithDeserialization 实例仅在会话期间有效。当 serverSentEvents { ... } 块完成或连接关闭时,它们的作用域会自动取消。
+ 此外,还有以下形参可用于配置连接:
+reconnectionTimeshowCommentEventsshowRetryEventsretry 字段的事件。
+ deserializeTypedServerSentEvent 的 data 字段转换为对象。更多信息请参阅 反序列化。
+
+ 在 lambda 实参中,您可以访问 ClientSSESession 上下文。该块中提供以下属性:
+
callHttpClientCall。
+ incoming
+ 下面的示例创建了一个具有 events 端点的新 SSE 会话,通过 incoming 属性读取事件并打印接收到的 ServerSentEvent。
+
有关完整示例,请参阅 client-sse。
++ SSE 插件支持将服务器发送事件反序列化为类型安全的 Kotlin 对象。当处理来自服务器的结构化数据时,此功能特别有用。 +
+
+ 要启用反序列化,请在 SSE 访问函数上使用 deserialize 形参提供自定义反序列化函数,并使用 ClientSSESessionWithDeserialization 类来处理反序列化后的事件。
+
+ 以下是使用 kotlinx.serialization 反序列化 JSON 数据的示例:
+
有关完整示例,请参阅 client-sse。
+
+ 所需依赖:io.ktor:ktor-client-websockets
+
+ 代码示例: + + %example_name% + +
+客户端的 Websockets 插件允许您处理与服务器交换消息的 WebSocket 会话。
+并非所有引擎都支持 WebSockets。有关受支持引擎的概览,请参阅限制。
+要了解服务器端的 WebSocket 支持,请参阅
要使用 WebSockets,您需要在构建脚本中包含 %artifact_name% 构件:
要安装 WebSockets 插件,请在 客户端配置块 内部将其传递给 install 函数:
(可选)您可以通过在 install 块内传递
+ WebSockets.Config 支持的属性来配置插件。
+
maxFrameSizeFrame 大小。
+ contentConverterpingIntervalMillisLong 格式指定 ping 之间的时间间隔。
+ pingIntervalDuration 格式指定 ping 之间的时间间隔。
+ pingInterval 和 pingIntervalMillis 属性不适用于 OkHttp 引擎。要为 OkHttp 设置 ping 间隔,您可以使用 引擎配置:
+
+ 在以下示例中,WebSockets 插件配置了 20 秒(20_000 毫秒)的 ping 间隔,以自动发送 ping 帧并保持 WebSocket 连接处于活动状态:
+
客户端的 WebSocket 会话由 + DefaultClientWebSocketSession + 接口表示。该接口公开了允许您发送和接收 WebSocket 帧以及关闭会话的 API。 +
+
+ HttpClient 提供了两种访问 WebSocket 会话的主要方式:
+
webSocket()
+ 函数接受 DefaultClientWebSocketSession 作为块参数。
DefaultClientWebSocketSession 实例,并允许您在 runBlocking 或 launch 作用域之外访问会话。
+ 在函数块内,您可以为指定的路径定义处理程序。块内提供以下函数和属性:
+send()send() 函数向服务器发送文本内容。
+ outgoingoutgoing 属性访问用于发送 WebSocket 帧的通道。帧由 Frame 类表示。
+ incomingincoming 属性访问用于接收 WebSocket 帧的通道。帧由 Frame 类表示。
+ close()close() 函数发送带有指定原因的关闭帧。
+ + 您可以检查 WebSocket 帧的类型并进行相应处理。一些常见的帧类型包括: +
+Frame.Text 表示文本帧。使用
+ Frame.Text.readText() 读取其内容。
+ Frame.Binary 表示二进制帧。使用 Frame.Binary.readBytes()
+ 读取其内容。
+ Frame.Close 表示关闭帧。使用 Frame.Close.readReason()
+ 获取会话关闭的原因。
+ 下面的示例创建了 echo WebSocket 端点,并展示了如何向服务器发送消息以及从服务器接收消息。
有关完整示例,请参阅 client-websockets。
+
+
+
在本主题中,我们将向您展示如何在 Docker Compose 下运行 Ktor 服务器应用程序。我们将使用在
+ 在 配置数据库连接 教程中创建的项目使用硬编码属性来建立数据库连接。
+
+ 让我们将 PostgreSQL 数据库的连接设置提取到
打开 ktor 组之外添加 storage 组,如下所示:
+
这些设置稍后将在
+
+ 打开 configureDatabases() 函数,以从配置文件加载存储设置:
+
+ configureDatabases() 函数现在接受 ApplicationConfig,并使用 config.property 加载自定义设置。
+
+ 打开 environment.config 传递给 configureDatabases(),以便在应用程序启动时加载连接设置:
+
为了在 Docker 上运行,应用程序需要将所有必需的文件部署到容器。根据您使用的构建系统,有不同的插件可以实现这一点:
+在我们的示例中,
+ 要将应用程序 Docker 化,请在项目的根目录中创建一个新的
+ 本示例使用的是 Amazon Corretto Docker 镜像,但您可以将其替换为任何其他合适的替代品,例如: +
+在项目的根目录中,创建一个新的
web 服务用于运行打包在 镜像 内的 Ktor 应用程序。
+ db 服务使用 postgres 镜像创建 ktor_tutorial_db 数据库以存储任务。
+ + 运行以下命令以创建包含 Ktor 应用程序的 fat JAR: +
+
+ 使用 docker compose up 命令构建镜像并启动容器:
+
+ 导航至 http://localhost:8080/static/index.html 以打开 Web 应用程序。您应该会看到“任务管理器客户端”页面,其中显示了三个用于筛选和添加新任务的表单,以及一个任务表。 +
+
+ + 代码示例: + + %example_name% + +
+
+ 使用的插件:
+ 在本文中,你将学习如何使用 Kotlin 开发运行在 Android、iOS、Web 和桌面平台的全栈应用程序,同时利用 Ktor 进行无缝的数据处理。 +
+在本教程结束时,你将了解如何执行以下操作:
+
+ 在之前的教程中,我们使用任务管理器(Task Manager)示例来
+
+ 你将创建一个面向 Android、iOS、Web 和桌面平台的客户端,并使用 Ktor 服务获取要显示的数据。你将尽可能在客户端和服务器之间共享数据类型,从而加快开发速度并减少出错的可能性。 +
++ 与之前的文章一样,你将使用 IntelliJ IDEA 作为 IDE。要安装和配置环境,请参阅 + + Kotlin Multiplatform 快速入门指南 + + 。 +
++ 如果这是你第一次使用 Compose Multiplatform,我们建议你在开始本教程之前先完成 + + Compose Multiplatform 入门 + + 教程。为了降低任务的复杂度,你可以专注于单一的客户端平台。例如,如果你从未用过 iOS,那么专注于桌面端或 Android 开发可能是明智之举。 +
++ 不使用 Ktor 项目生成器,而是使用 IntelliJ IDEA 中的 Kotlin Multiplatform 项目向导。 + 它将创建一个基础的多平台项目,你可以通过客户端和服务对其进行扩展。客户端可以使用原生 UI 库(如 SwiftUI),但在本教程中,你将使用 Compose Multiplatform 为所有平台创建一个共享 UI。 +
+
+ 选择
+
+ 如果你使用的是 Mac,也请选择
+
+
+ 点击
+
+
+
+ 导航至 http://0.0.0.0:8080/ 以打开应用程序。
+ 你应该会看到浏览器中显示的来自 Ktor 的消息。
+
+
+
+
+
+ 如果你查看
+ sayHello() 函数的调用:
+
+ sayHello() 函数定义在
+
+ 打开 sayHello() 函数也在那里被使用了:
+
+
+
+ 例如,在 Greeting 类型中,当前平台的名称是使用平台特定的 API,通过 预期声明 (expect) 和实际声明 (actual) 获取的。
+
+ 在
+ getPlatform() 函数使用 expect 关键字声明:
+
+ 然后,每个目标平台都提供 getPlatform() 函数的一个 actual 声明,如下所示:
+
+ 你可以通过执行目标的运行配置来运行客户端应用程序。要在 iOS 模拟器(Simulator)上运行应用程序,请按照以下步骤操作: +
+
+
+ 运行 iOS 应用时,它会在后台通过 Xcode 进行构建并在 iOS 模拟器中启动。
+ 应用会显示一个按钮,点击后可以切换图片的显示。
+
+
+ 第一次按下按钮时,当前平台的详细信息会添加到按钮文本中。实现此功能的代码位于
+
+ 这是一个可组合函数,你将在本文后面部分对其进行修改。目前,重要的是它显示了一个 UI,并使用了共享的 Greeting 类型,而该类型又使用了实现通用 Platform 接口的平台特定类。
+
+ 现在你已经了解了生成的项目的结构,可以逐步添加任务管理器功能。 +
++ 首先,添加模型类型,并确保它们对于客户端和服务器都是可访问的。 +
+kotlinx.serialization 依赖项:
+
+ 导航至
+
+ 在同一文件中,向
+
+ 添加一个表示优先级的枚举和一个表示任务的类。
+ Task
+ 类使用来自
+ kotlinx.serialization
+ 库的 Serializable 注解:
+
+ 下一阶段是为任务管理器创建服务器实现。 +
+
+ 在此包内,创建一个新的
+
+ 在同一包中,创建一个名为
+
+ 导航至
+
+ 此实现与之前教程中的非常相似,不同之处在于,为了简单起见,现在你已将所有路由代码放置在 Application.module() 函数中。
+
+ 输入此代码并添加导入后,你会发现多个编译器错误,因为代码使用了多个需要作为依赖项包含的 Ktor 插件,包括用于与 Web 客户端交互的
+ 打开服务器模块构建文件 (
+
ContentNegotiation 类型和 json() 函数的导入可以正常工作。
+ + 为了让你的客户端能够访问服务器,你需要包含 Ktor Client。这涉及三种类型的依赖项: +
+
+ 完成后,你可以添加一个 TaskApi 类型,作为你的客户端围绕 Ktor Client 的薄封装。
+
+ 在新包内,创建一个新的
+
+ 将 1.2.3.4 替换为你当前机器的 IP 地址。你将无法从运行在 Android 虚拟设备或 iOS 模拟器上的代码中调用 0.0.0.0 或 localhost。
+
查找你的 IP 地址:
+
+ 由于移动端模拟器无法访问 localhost,你需要机器的实际 IP 地址。要查找你的 IP 地址,请运行以下命令之一:
+
ifconfig | grep "inet " | grep -v 127.0.0.1hostname -I | awk '{print $1}'ipconfig 并查找“IPv4 地址”
+ 在同一个
+
+ 导航至
+ TaskApi 类型从服务器检索任务列表,然后在一个列中显示每个任务的名称:
+
+ 在服务器运行的同时,通过运行
+ 点击
+
+
+ 在 Android 平台上,你需要明确授予应用程序网络权限,并允许其以明文形式发送和接收数据。要启用这些权限,请打开
+
+ 使用
+
+ 对于桌面端客户端,你将为包含的窗口分配尺寸和标题。
+ 打开文件
+ title 和设置 state 属性来修改代码:
+
+ 使用
+
+ 使用以下运行配置之一运行 Web 客户端: +
+
+ + 现在客户端正在与服务器通信,但其 UI 显然不够吸引人。 +
+
+ 打开位于
+ App 和 TaskCard 可组合项替换现有的 App:
+
+ 通过这一实现,你的客户端现在已经具备了一些基本功能。 +
+
+ 通过使用 LaunchedEffect 类型,所有任务都会在启动时加载,而 LazyColumn 可组合项允许用户滚动浏览任务。
+
+ 最后,创建了一个独立的 TaskCard 可组合项,它反过来使用 Card 来显示每个 Task 的详细信息。添加了用于删除和更新任务的按钮。
+
+ 重新运行客户端应用程序——例如 Android 应用。
+ 你现在可以滚动浏览任务、查看其详细信息并删除它们:
+
+
+ 为了完善客户端,加入允许更新任务详细信息的功能。 +
+
+ 添加 UpdateTaskDialog 可组合项和必要的导入,如下所示:
+
+ 这是一个使用对话框显示 Task 详细信息的可组合项。description 和 priority 被放置在 TextField 可组合项中,以便它们可以被更新。当用户按下更新按钮时,它会触发 onConfirm() 回调。
+
+ 在同一个文件中更新 App 可组合项:
+
+ 你正在存储一个额外的状态片段,即当前选定的任务。如果该值不为 null,那么我们就调用 UpdateTaskDialog 可组合项,并将 onConfirm() 回调设置为使用 TaskApi 向服务器发送 POST 请求。
+
+ 最后,在创建 TaskCard 可组合项时,你使用 onUpdate() 回调来设置 currentTask 状态变量。
+
+ + 在本文中,你已在 Kotlin Multiplatform 应用程序的环境中使用了 Ktor。你现在可以创建一个包含多个服务和客户端的项目,目标平台涵盖一系列不同的平台。 +
+
+ 如你所见,构建功能而不产生任何代码重复或冗余是可能的。项目各层所需的类型可以放置在
+
+ 这种开发方式不可避免地需要客户端和服务器端技术的知识。但你可以使用 Kotlin Multiplatform 库和 Compose Multiplatform 来最大限度地减少你需要学习的新材料。即使你的重点最初只在单一平台上,你也可以随着对应用程序需求的增长轻松添加其他平台。 +
++ 代码示例: + migrating-express + migrating-express-ktor +
++ 在本指南中,我们将了解在基本场景下如何将 Express 应用程序迁移到 Ktor:从生成应用程序和编写第一个应用程序,到创建用于扩展应用程序功能的中间件。 +
+|
+ |
+
+
+ 你可以使用 |
+
|
+ |
+
+ + Ktor 提供了以下方式来生成应用程序骨架: + +
+Ktor 项目生成器 — 使用基于 Web 的生成器。 + +
+
+ Ktor 命令行工具
+ — 通过命令行界面使用 + + Yeoman 生成器 + + — 以交互方式配置项目设置并选择所需的插件: + ++IntelliJ IDEA Ultimate — 使用内置的 Ktor 项目向导。 + +
+ 有关详细说明,请参阅 |
+
+ 在本节中,我们将了解如何创建最简单的服务器应用程序,该程序接受 GET 请求并响应预定义的纯文本。
+
|
+ |
+
+
+ 下面的示例展示了启动服务器并侦听端口 + 有关完整示例,请参阅 + 1_hello + 项目。 + + |
+
|
+ |
+
+ + 在 Ktor 中,你可以使用 embeddedServer 函数在代码中配置服务器参数并快速运行应用程序。 + ++ 有关完整示例,请参阅 + 1_hello + 项目。 + ++ 你还可以在使用 HOCON 或 YAML 格式的 外部配置文件 中指定服务器设置。 + + |
+
+ 请注意,上述 Express 应用程序添加了
+ 要在 Ktor 的每个响应中添加默认的
+ 在本节中,我们将了解如何在 Express 和 Ktor 中提供静态文件,例如图像、CSS 文件和 JavaScript 文件。假设我们有一个包含主
|
+ |
+
+
+ 在 Express 中,将文件夹名称传递给 + 有关完整示例,请参阅 + 2_static + 项目。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,使用 + 有关完整示例,请参阅 2_static + 项目。 + + |
+
+ 提供静态内容时,Express 会添加多个响应头,如下所示: +
++ 要在 Ktor 中管理这些标头,你需要安装以下插件: +
+
+
+
+
+ GET、POST 等)和路径定义。下面的示例展示了如何处理发送到 GET 和 POST 请求。
+
|
+ |
+
+ + 有关完整示例,请参阅 + 3_router + 项目。 + + |
+
|
+ |
+
+
+ 请参阅 接收请求,了解如何接收 + 有关完整示例,请参阅 + 3_router + 项目。 + + |
+
+ 以下示例演示了如何按路径对路由处理程序进行分组。 +
+|
+ |
+
+
+ 在 Express 中,你可以使用 + 有关完整示例,请参阅 + 3_router + 项目。 + + |
+
|
+ |
+
+
+ Ktor 提供了一个 + 有关完整示例,请参阅 + 3_router + 项目。 + + |
+
+ 这两个框架都允许你在单个文件中对相关路由进行分组。 +
+|
+ |
+
+
+ Express 提供了 + 有关完整示例,请参阅 + 3_router + 项目。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,一种常见的模式是在 + 有关完整示例,请参阅 + 3_router + 项目。 + + |
+
+ 除了将 URL 路径指定为字符串外,Ktor 还包含实现
+ 本节将展示如何访问路由参数和查询参数。 +
++ 路由(或路径)参数是命名的 URL 段,用于捕获 URL 中其所在位置指定的值。 +
+|
+ |
+
+
+ 要在 Express 中访问路由参数,你可以使用 + 有关完整示例,请参阅 + 4_parameters + 项目。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,路由参数使用 + 有关完整示例,请参阅 + 4_parameters + 项目。 + + |
+
+ 下表比较了如何访问查询字符串的参数。 +
+|
+ |
+
+
+ 要在 Express 中访问路由参数,你可以使用 + 有关完整示例,请参阅 + 4_parameters + 项目。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,路由参数使用 + 有关完整示例,请参阅 + 4_parameters + 项目。 + + |
+
+ 在前面的章节中,我们已经了解了如何响应纯文本内容。下面让我们看看如何发送 JSON、文件和重定向响应。 +
+|
+ |
+
+
+ 要在 Express 中发送具有适当内容类型的 JSON 响应,请调用 + 有关完整示例,请参阅 + 5_send_response + 项目。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,你需要安装
+ 要将数据序列化为 JSON,你需要创建一个带有
+ 然后,你可以使用 + 有关完整示例,请参阅 + 5_send_response + 项目。 + + |
+
|
+ |
+
+
+ 要在 Express 中响应一个文件,请使用 + 有关完整示例,请参阅 + 5_send_response + 项目。 + + |
+
|
+ |
+
+
+ Ktor 提供了 + 有关完整示例,请参阅 + 5_send_response + 项目。 + + |
+
+ Express 应用程序在响应文件时会添加
|
+ |
+
+
+ + 有关完整示例,请参阅 + 5_send_response + 项目。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,你需要手动配置 + 有关完整示例,请参阅 + 5_send_response + 项目。 + + |
+
|
+ |
+
+
+ 要在 Express 中生成重定向响应,请调用 + 有关完整示例,请参阅 + 5_send_response + 项目。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,使用 + 有关完整示例,请参阅 + 5_send_response + 项目。 + + |
+
+ Express 和 Ktor 都允许配合模板引擎来处理视图。 +
+|
+ |
+
+
+ 假设我们在
+ 要响应此模板,请调用 + 有关完整示例,请参阅 + 6_templates + 项目。 + + |
+
|
+ |
+
+
+ Ktor 支持多种 + 有关完整示例,请参阅 + 6_templates + 项目。 + + |
+
+ 本节将展示如何接收不同格式的请求体。 +
+
+ 下面的 POST 请求向服务器发送文本数据:
+
+ 让我们看看如何在服务器端以纯文本形式接收此请求的请求体。 +
+|
+ |
+
+
+ 要在 Express 中解析传入的请求体,你需要添加
+ 在 + 有关完整示例,请参阅 + 7_receive_request + 项目。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,你可以使用 + 有关完整示例,请参阅 + 7_receive_request + 项目。 + + |
+
+ 在本节中,我们将了解如何接收 JSON 请求体。下面的示例展示了一个请求体中包含 JSON 对象的 POST 请求:
+
|
+ |
+
+
+ 要在 Express 中接收 JSON,请使用 + 有关完整示例,请参阅 + 7_receive_request + 项目。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,你需要安装 + 要将接收到的数据反序列化为对象,你需要创建一个数据类: + +
+ 然后,使用接受此数据类作为参数的 + 有关完整示例,请参阅 + 7_receive_request + 项目。 + + |
+
+ 现在让我们看看如何接收使用 POST 请求示例:
+
|
+ |
+
+
+ 与纯文本和 JSON 一样,Express 需要 + 有关完整示例,请参阅 + 7_receive_request + 项目。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,请使用 + 有关完整示例,请参阅 + 7_receive_request + 项目。 + + |
+
+ 下一个用例是处理二进制数据。下面的请求向服务器发送一个类型为
|
+ |
+
+
+ 要在 Express 中处理二进制数据,请将解析器类型设置为 + 有关完整示例,请参阅 + 7_receive_request + 项目。 + + |
+
|
+ |
+
+
+ Ktor 提供了 + 有关完整示例,请参阅 + 7_receive + request + 项目。 + + |
+
+ 在最后一部分,让我们看看如何处理 POST 请求使用
|
+ |
+
+
+ Express 需要一个单独的模块来解析多部分数据。在下面的示例中,使用了 + 有关完整示例,请参阅 + 7_receive_request + 项目。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,如果你需要接收作为多部分请求一部分发送的文件,请调用 + 有关完整示例,请参阅 + 7_receive_request + 项目。 + + |
+
+ 我们要看的最后一件事是如何创建允许你扩展服务器功能的中间件。下面的示例展示了如何使用 Express 和 Ktor 实现请求日志记录。 +
+|
+ |
+
+
+ 在 Express 中,中间件是使用 + 有关完整示例,请参阅 + 8_middleware + 项目。 + + |
+
|
+ |
+
+
+ Ktor 允许你使用 + 有关完整示例,请参阅 + 8_middleware + 项目。 + + |
+
+ 本指南中还有许多未涵盖的用例,例如会话管理、授权、数据库集成等。对于大多数这些功能,Ktor 提供了专用插件,可以将其安装在应用程序中并根据需要进行配置。要继续你的 Ktor 之旅,请访问
+ 代码示例: + autoreload-engine-main, + autoreload-embedded-server +
+
+ 在开发过程中
| 模块类型 | +<= 3.2 | +> 3.2 | +
| Lambda 初始值设定项 | +❌ 不支持 | +❌ 不支持 | +
| 阻塞函数引用 | +✅ 支持 | +❌ 不支持 | +
| 挂起函数引用 | +❌ 不支持 | +✅ 支持 | +
| 配置引用 | +✅ 支持 | +✅ 支持 | +
+ 要使用自动重载,您需要先启用
+ 开发模式。
+ 这取决于您用于
+ 如果您使用 EngineMain 运行服务器,请在配置文件中启用开发模式。
+
+ 如果您使用 embeddedServer 运行服务器,可以使用
+ io.ktor.development
+ 系统属性。
+
+ 启用开发模式后,Ktor 将自动监视工作目录中的输出文件。 + 如有需要,您可以通过指定监视路径来缩小监视文件夹的范围。 +
+
+ 当您启用开发模式时,
+ Ktor 开始监视工作目录中的输出文件。
+ 例如,对于使用 Gradle 构建的
+ 监视路径允许您缩小监视文件夹的范围。
+ 为此,您可以指定监视路径的一部分。
+ 例如,要监控 classes 作为监视路径传递。
+ 根据您运行服务器的方式,您可以通过以下方式指定监视路径:
+
+ 在 watch 选项:
+
+ 您还可以指定多个监视路径,例如: +
++ 您可以在此处找到完整示例:autoreload-engine-main。 +
+
+ 如果您使用的是 embeddedServer,请将监视路径作为 watchPaths
+ 形参传递:
+
+ 有关完整示例,请参阅 + + autoreload-embedded-server + + 。 +
+
+ 由于自动重载检测的是输出文件中的更改,
+ 因此您需要重新构建项目。
+ 您可以在 IntelliJ IDEA 中手动执行此操作,或者
+ 使用 -t 命令行选项在 Gradle 中启用持续构建执行。
+
+ 要在 IntelliJ IDEA 中手动重新构建项目,请从主菜单选择
+
+ 要使用 Gradle 自动重新构建项目,
+ 您可以在终端中使用 -t 选项运行 build 任务:
+
+ 要在重载项目时跳过运行测试,可以将 -x 选项传递给 build 任务:
+
+ Ktor 允许您直接在代码中配置各种服务器参数,包括主机地址、端口、
+ 使用 embeddedServer 时,您可以通过将所需参数直接传递给该函数来配置服务器。
+
+ embeddedServer
+
+ 函数接受用于配置服务器的不同形参,包括
+ 在本节中,我们将查看几个运行 embeddedServer 的不同示例,说明如何根据您的需要配置服务器。
+
+ 下面的代码段展示了使用 Netty 引擎和 8080 端口的基础服务器设置。
+
+ 请注意,您可以将 port 形参设置为 0 以在随机端口上运行服务器。
+ embeddedServer 函数会返回一个引擎实例,因此您可以在代码中使用
+
+ ApplicationEngine.resolvedConnectors
+
+ 函数获取端口值。
+
+ embeddedServer 函数允许您使用 configure 形参传递引擎特定的选项。该形参包含所有引擎通用的选项,由
+
+ ApplicationEngine.Configuration
+
+ 类提供。
+
+ 下面的示例展示了如何使用 Netty 引擎配置服务器。在 configure 块中,我们定义了一个 connector(连接器)来指定主机和端口,并自定义了各种服务器参数:
+
+ connectors.add() 方法使用指定的主机 (127.0.0.1) 和端口 (8080) 定义了一个连接器。
+
除了这些选项之外,您还可以配置其他特定于引擎的属性。
++ Netty 特定的选项由 + + NettyApplicationEngine.Configuration + + 类提供。 +
++ Jetty 特定的选项由 + + JettyApplicationEngineBase.Configuration + + 类提供。 +
+您可以在 + + configureServer + + 块中配置 Jetty 服务器,该块提供了对 + Server + 实例的访问。 +
+
+ 使用 idleTimeout 属性来指定连接在关闭之前可以空闲的时间长度。
+
CIO 特定的选项由 + + CIOApplicationEngine.Configuration + + 类提供。 +
+如果您使用 Tomcat 作为引擎,您可以使用 + + configureTomcat + + 属性进行配置,该属性提供了对 + Tomcat + 实例的访问。 +
++ 下面的示例展示了如何使用由 + + ApplicationEngine.Configuration + + 类表示的自定义配置运行带有多个连接器端点的服务器。 +
++ 有关完整示例,请参阅 + + embedded-server-multiple-connectors + 。 +
++ 您还可以使用自定义环境来 + + 提供 HTTPS 服务 + 。 +
+
+ Ktor 允许您使用命令行实参动态配置 embeddedServer。在需要在运行时指定端口、主机或超时等配置的情况下,这特别有用。
+
+ 为了实现这一点,请使用 + + CommandLineConfig + + 类将命令行实参解析为配置对象,并将其在配置块中传递: +
+
+ 在此示例中,来自 Application.Configuration 的
+
+ takeFrom()
+
+ 函数被用于替代引擎配置值,例如 port 和 host。
+
+ loadCommonConfiguration()
+
+ 函数从根环境加载配置,例如超时设置。
+
+ 要运行服务器,请按以下方式指定实参: +
++ 代码示例: + + %example_name% + +
++ 在本教程中,您将学习如何创建、打开并运行您的第一个 Ktor 服务器项目。一旦运行起来,您就可以完成一系列任务来熟悉 Ktor。 +
++ 这是关于使用 Ktor 构建服务器应用程序入门系列教程的第一部分。您可以独立完成每个教程,但我们强烈建议您按照建议的顺序进行: +
++ 创建新 Ktor 项目最快的方法之一是 使用基于 Web 的 Ktor 项目生成器。 +
++ 或者,您也可以 使用专用的 IntelliJ IDEA Ultimate Ktor 插件 或 Ktor CLI 工具 生成项目。 +
++ 要使用 Ktor 项目生成器创建新项目,请按照以下步骤操作: +
+导航至 Ktor 项目生成器。
+在
+
+
点击
+
+
+ 提供以下设置: +
+
+
+
+
对于本教程,您可以保留这些设置的默认值。
+点击
+
在下方您会发现一组可以添加到项目中的
就本教程而言,您目前不需要添加任何插件。
+
+ 点击
+
+
下载应会自动开始。
+现在您已经生成了新项目,请继续 解压缩并运行您的 Ktor 项目。
++ 本节介绍如何使用 IntelliJ IDEA Ultimate 的 Ktor 插件 进行项目设置。 +
++ 要创建一个新的 Ktor 项目,请 打开 IntelliJ IDEA 并按照以下步骤操作: +
+
+ 在欢迎屏幕上,点击
+ 或者,从主菜单中选择
+ 在
+
+ 在右侧面板中,您可以指定以下设置: +
+
+
+
+
+
+
+
+
+ 点击
+
+ + 提供以下设置: +
+
+
+
+
就本教程而言,您可以保留这些设置的默认值。
+
+ 点击
+
+
+ 在此页面上,您可以选择一组
就本教程而言,您目前不需要添加任何插件。
+
+ 点击
+
+ 现在您已经创建了新项目,请继续学习如何 打开、探索并运行 应用程序。 +
++ 本节介绍如何使用 Ktor CLI 工具 进行项目设置。 +
++ 要创建一个新的 Ktor 项目,请打开您选择的终端并按照以下步骤操作: +
+
+
+ (可选)您还可以通过编辑项目名称下方的
+ 就本教程而言,您目前不需要添加任何插件。
+
+ 或者,您可以通过选择
+
+ 在本节中,您将学习如何从命令行解压缩、构建和运行项目。以下步骤假设: +
+如有必要,请更改名称和路径以匹配您自己的设置。
+打开您选择的命令行工具并按照以下步骤操作:
+在终端窗口中,导航到您下载项目的文件夹:
+将 ZIP 存档解压缩到同名文件夹中:
+您的目录现在将包含 ZIP 存档和解压后的文件夹。
+从该目录进入新创建的文件夹:
+在 macOS 和 UNIX 系统上,您必须使 Gradle 辅助脚本具有可执行权限,以便系统将其识别为可运行命令。为此,请使用 chmod 命令:
要构建项目,请使用以下命令:
+构建成功后,继续执行下一步以运行项目。
+要运行项目,请使用以下命令:
+要验证项目是否正在运行,请在浏览器中打开终端输出显示的 URL(http://0.0.0.0:8080)。 + 您应该在浏览器中看到显示的消息 "Hello World!":
+
+ 恭喜!您已成功启动了 Ktor 项目。
+如果您安装了 IntelliJ IDEA,可以轻松地从命令行打开项目。 +
+
+ 确保您位于项目文件夹中,然后输入 idea 命令,后跟一个点(代表当前文件夹):
+
+ 或者,要手动打开项目,请启动 IntelliJ IDEA。 +
+
+ 如果显示欢迎屏幕,请点击
+
打开项目后,您可以看到以下结构:
+
+
+ 要查看完整布局,请点击每个文件夹旁边的展开箭头,展开
+ 应用程序源代码位于
+
+ 项目的名称在
+
+ 配置文件以及其他类型的内容存放在
+
+ 要在 IntelliJ IDEA 内部运行项目:
+点击右侧侧边栏上的 Gradle 图标()打开 Gradle 工具窗口。
在此工具窗口中,导航到
+
+ 您的 Ktor 应用程序将在 IDE 底部的 Run 工具窗口 中启动:
+
+ 之前在命令行上显示的相同消息现在将在
+
要确认项目正在运行,请在浏览器中打开指定的 URL + (http://0.0.0.0:8080)。
+您应该会再次看到屏幕上显示消息 "Hello World!":
+
+
+ 您可以通过
+
+ 这些选项在 IntelliJ IDEA Run 工具窗口文档 中有进一步解释。 +
+以下是您可能希望尝试的一些其他任务:
++ 这些任务彼此不依赖,但复杂程度逐渐增加。按声明的顺序尝试它们是递进学习最简单的方法。为简单起见并避免重复,下面的描述假设您按顺序尝试任务。 +
++ 在需要编码的地方,我们指定了代码和相应的导入。IDE 可能会为您自动添加这些导入。 +
+
+ 如果您选择将配置存储在外部的 YAML 或 HOCON 文件中,请在
+
port 值更改为您选择的另一个数字,例如
+ 9292。
+ 点击重新运行按钮()以重新启动应用程序。
要验证您的应用程序是否在新端口号下运行,您可以在浏览器中打开新 URL(http://0.0.0.0:9292)或 在 IntelliJ IDEA 中创建一个新的 HTTP Request 文件:
+
+ + 创建新的 Ktor 项目时,您可以选择在代码中或在外部的 YAML 或 HOCON 文件中存储配置。 +
+
+ 如果您选择了在代码中存储配置的选项,请在
+
打开
+
在 embeddedServer() 函数中,将 port 形参更改为您选择的另一个数字,例如 9292。
点击重新运行按钮()以重新启动应用程序。
要验证您的应用程序是否在新端口号下运行,您可以在浏览器中打开新 URL(http://0.0.0.0:9292),或者 在 IntelliJ IDEA 中创建一个新的 HTTP Request 文件:
+
+
+ 在
+
打开
+
要创建新端点,请按照下文所示插入额外的路由:
+/test1 URL 更改为任何您喜欢的名称。IDE 会自动添加 ContentType 的导入:
点击重新运行按钮()以重新启动应用程序。
在浏览器中请求新的 URL(http://0.0.0.0:9292/test1)。端口号取决于您是否完成了 更改默认端口 任务。您应该看到如下所示的输出:
+
+ 如果您创建了 HTTP 请求文件,也可以在其中验证新端点:
+###)的一行来分隔不同的请求。在
+
打开
这一行的含义如下:
+staticResources() 使您的应用程序能够提供标准网站内容,例如 HTML 和 JavaScript 文件。虽然这些内容可以在浏览器中执行,但从服务器的角度来看,它们被认为是静态的。
+ /content 指定了用于获取此路径的路径。
+ mycontent 是静态内容所在的文件夹名称。Ktor 将在 resources 目录中查找此文件夹。
+ 如果 IDE 没有自动添加,请添加以下导入。
+在
+
或者,选择
将新目录命名为 mycontent 并按
+
右键点击新创建的文件夹并点击
+
将新文件命名为
在新创建的文件中填充有效的 HTML,例如:
+点击重新运行按钮()以重新启动应用程序。
当您在浏览器中打开 http://0.0.0.0:9292/content/sample.html 时,应显示示例页面的内容:
+
+
+ Ktor 支持
要利用此功能,请按照以下步骤操作:
+
+ 导航至
+
打开
testApplication() 函数创建一个新的 Ktor 实例。该实例运行在测试环境中,而不是像 Netty 这样的服务器中。
然后您可以使用 configure() 函数来调用与 embeddedServer() 中调用的相同的设置。
最后,您可以使用内置的 client 对象和 JUnit 断言来发送示例请求并检查响应。
+ 您可以使用在 IntelliJ IDEA 中执行测试的任何标准方式运行测试。请注意,因为您正在运行一个新的 Ktor 实例,所以测试的成功或失败并不取决于您的应用程序是否正在 0.0.0.0 运行。
+
+ 如果您已成功完成了 添加新的 HTTP 端点,请添加此额外测试: +
+添加以下额外的导入:
+
+ 您可以使用
+ 在接下来的步骤中,您将学习如何手动添加和配置该插件。实现此目标共有四个步骤: +
+ +在
+
打开
通过按
+
导航到 .configureRouting() 方法并添加以下代码行:
这些行安装了 StatusPages 插件,并指定了当抛出 IllegalStateException 类型的异常时应采取的操作。
添加以下导入:
++ 请注意,响应中通常会设置 HTTP 错误码,但出于本任务的目的,输出直接显示在浏览器中。 +
+继续在 .configureRouting() 方法中,按下文所示添加额外的路由:
您现在已添加了一个 URL 为 /error-test 的端点。当触发此端点时,将抛出处理程序中使用的类型的异常。
点击重新运行按钮()以重新启动应用程序。
在浏览器中,导航至 URL http://0.0.0.0:9292/error-test。您应该看到如下所示的错误消息:
+
+ + 如果您已经完成了上述附加任务,那么您现在已经掌握了如何配置 Ktor 服务器、集成 Ktor 插件以及实现新路由。然而,这仅仅是个开始。要更深入地了解 Ktor 的基础概念,请继续学习本指南中的下一个教程。 +
+
+ 接下来,您将学习如何
+ 代码示例: + embedded-server、 + engine-main、 + engine-main-yaml +
+
+ 在创建 Ktor 应用之前,您需要考虑应用将如何
+ 作为
+ 在此情况下,用于处理网络请求的应用
+ 作为
+
+ 在此情况下,Ktor 应用可以部署在 servlet 容器(如 Tomcat 或 Jetty)中,容器负责控制应用的生命周期和连接设置。 +
+
+ 要将 Ktor 服务器应用作为自包含包交付,您首先需要创建一个服务器。服务器配置可以包含不同的设置:服务器
+ embeddedServer函数是在代码中配置服务器参数并快速运行应用的简单方法。
+
+ EngineMain提供了更灵活的服务器配置方式。您可以在文件中指定服务器参数,并在无需重新编译应用的情况下更改配置。此外,您可以从命令行运行应用,并通过传递相应的命令行实参来覆盖所需的服务器参数。
+
+ embeddedServer函数是在引擎和端口作为形参来启动服务器。在以下示例中,我们使用Netty引擎运行服务器并侦听8080端口:
+
+ 有关完整示例,请参阅embedded-server。 +
+
+ EngineMain启动带有选定引擎的服务器,并从外部resource目录中的
+ 除了指定要加载的模块外,配置文件还可以包含各种服务器参数,例如端口、主机和 SSL 设置。例如,下面的配置将服务器端口设置为8080。
+
EngineMain.main()启动服务器外,您还可以使用EngineMain.createServer()手动创建服务器实例。要了解更多信息,请参阅。
+ + 有关完整示例,请参阅engine-main和engine-main-yaml。 +
+
+ Ktor 应用可以在包含 Tomcat 和 Jetty 在内的 servlet 容器中运行和部署。要部署在 servlet 容器中,您需要生成
+ 代码示例: + + %example_name% + +
+
+ 使用的插件:
+ 在本教程中,我们将说明如何使用 Kotlin 和 Ktor 构建后端服务,并以一个生成 JSON 文件的 RESTful API 为例。 +
+
+ 在
+ 您将学习如何执行以下操作: +
+您可以独立完成本教程,但我们强烈建议您先完成上一篇教程,以学习如何
我们建议您安装 IntelliJ IDEA,但您也可以使用其他自选 IDE。 +
+在本教程中,您将把现有的任务管理器重写为 RESTful 服务。为此,您将使用多个 Ktor
+ 虽然您可以手动将其添加到现有项目中,但生成一个新项目然后逐步添加上一篇教程中的代码会更简单。您将在过程中重新编写所有代码,因此无需手头备有之前的项目。 +
++ 导航至 + Ktor 项目生成器。 +
+在
+
+
+ 在插件部分搜索并通过点击
+
+
+ 添加插件后,您将看到项目设置下方列出的所有插件。
+
+
+ 点击
+
在 IntelliJ IDEA 中打开您的项目,如之前的在 IntelliJ IDEA 中打开、探索并运行您的 Ktor 项目教程中所述。
+
+ 导航至
+
+ 在
+
+ 打开
+ enum 来表示优先级,以及一个 class 来表示任务:
+
+ 在上一篇教程中,您使用了扩展函数将 Task 转换为 HTML。在本例中,
+ Task 类被标注了来自
+ kotlinx.serialization 库的 Serializable
+ 类型。
+
+ 打开
+
+ 与上一篇教程类似,您为指向 URL /tasks 的 GET 请求创建了一个路由。这次,您无需手动转换任务列表,而是直接返回该列表。
+
在 IntelliJ IDEA 中,点击运行按钮
+ ()
+ 以启动应用程序。
+ 在浏览器中导航至 http://0.0.0.0:8080/tasks。您应该会看到 JSON 版本的任务列表,如下所示: +
+
+ 显然,系统已经为我们完成了大量工作。这背后的机制究竟是什么?
+
+ 当您创建项目时,已经包含了
+ 在 HTTP 中,客户端通过 Accept 标头告知其可以渲染的内容类型。该标头的值是一个或多个内容类型。在上述示例中,您可以使用浏览器内置的开发者工具来检查此标头的值。
+
+ 请看以下示例: +
+请注意 */* 的包含。此标头表明它接受 HTML、XML 或图像——但它也接受任何其他内容类型。
内容协商插件需要找到一种格式将数据发送回浏览器。如果您查看项目中生成的代码,会在
+
+ 此代码安装了 ContentNegotiation 插件,并配置了 kotlinx.serialization 插件。有了这个配置,当客户端发送请求时,服务器可以发回被序列化为 JSON 的对象。
+
+ 在来自浏览器的请求中,ContentNegotiation 插件知道它只能返回 JSON,而浏览器会尝试显示发送给它的任何内容。因此请求成功。
+
+ 在生产环境中,您通常不会直接在浏览器中显示 JSON。相反,在浏览器中运行的 JavaScript 代码会发出请求,然后将返回的数据作为单页应用程序 (SPA) 的一部分进行显示。通常,此类应用程序是使用 React、Angular 或 Vue.js 等框架编写的。 +
+
+ 为了模拟这一点,请打开
+
+ 此页面包含一个 HTML 表单和一个空表格。提交表单后,JavaScript 事件处理程序会向 /tasks 端点发送请求,并将 Accept 标头设置为 application/json。然后,返回的数据将被反序列化并添加到 HTML 表格中。
+
+ 在 IntelliJ IDEA 中,点击重新运行按钮()以重启应用程序。
+
+ 导航至 URL http://0.0.0.0:8080/static/index.html。您应该可以通过点击
+
+
+ 现在您已经熟悉了内容协商的过程,请继续将
+ 您可以无需任何修改地重用任务仓库,所以我们先来完成这一步。 +
+
+ 在
+
+ 打开
+
+ 现在您已经创建了仓库,可以实现 GET 请求的路由。之前的代码可以简化,因为您不再需要担心将任务转换为 HTML 的问题: +
+
+ 导航至
+
+ 使用以下实现更新 Application.configureRouting() 函数中 /tasks 路由的代码:
+
+ 有了这些,您的服务器就可以响应以下 GET 请求:
+/tasks 返回仓库中的所有任务。/tasks/byName/{taskName} 返回按指定的 taskName 过滤的任务。
+ /tasks/byPriority/{priority} 返回按指定的 priority 过滤的任务。
+
+ 在 IntelliJ IDEA 中,点击重新运行按钮()以重启应用程序。
+
您可以在浏览器中测试这些路由。例如,导航至 http://0.0.0.0:8080/tasks/byPriority/Medium,即可看到所有以 JSON 格式显示的 Medium 优先级任务:
+ + 鉴于此类请求通常来自 JavaScript,因此采用更精细的测试方式更为理想。为此,您可以使用诸如 Postman 之类的专门工具。 +
+在 Postman 中,创建一个 URL 为 http://0.0.0.0:8080/tasks/byPriority/Medium 的新 GET 请求。
+ 在
+ application/json。
+
点击
+
+ 在 IntelliJ IDEA Ultimate 中,您可以在 HTTP 请求文件中执行相同的步骤。
+
+ 在项目根目录中,创建一个新的
+
+ 打开
+
+ 要在 IntelliJ IDEA 中发送请求,点击它旁边的装订区域图标()。
+
这将在
+
+
+ 在上一篇教程中,任务是通过 HTML 表单创建的。然而,既然您现在正在构建 RESTful 服务,就不再需要那样做了。相反,您将利用 kotlinx.serialization 框架,它将完成大部分繁重的工作。
+
+ 打开
+
+ 向 Application.configureRouting() 函数添加一个新的 POST 路由,如下所示:
+
+ 添加以下新导入: +
+
+ 当向 /tasks 发送 POST 请求时,kotlinx.serialization 框架被用于将请求体转换为 Task 对象。如果成功,任务将被添加到仓库中。如果反序列化过程失败,服务器将处理 SerializationException,而如果任务重复,则处理 IllegalStateException。
+
+ 重启应用程序。 +
+
+ 要在 Postman 中测试此功能,请创建一个指向 URL http://0.0.0.0:8080/tasks 的新 POST 请求。
+
+ 在
+
+ 点击
+
+ 您可以通过向 http://0.0.0.0:8080/tasks 发送 GET 请求来验证任务是否已被添加。 +
++ 在 IntelliJ IDEA Ultimate 中,您可以通过在 HTTP 请求文件中添加以下内容来执行相同的步骤: +
++ 您即将完成向服务添加基础操作的工作。这些操作通常被简称为 CRUD(创建、读取、更新和删除)操作。现在您将实现删除操作。 +
+
+ 在
+ TaskRepository 对象内添加以下方法以根据名称移除任务:
+
+ 打开
+ routing() 函数中添加一个端点来处理 DELETE 请求:
+
+ 重启应用程序。 +
++ 将以下 DELETE 请求添加到您的 HTTP 请求文件: +
+
+ 要在 IntelliJ IDEA 中发送 DELETE 请求,点击它旁边的装订区域图标()。
+
您将在
+
+
+ 到目前为止,您已经手动测试了应用程序,但如您所见,这种方法耗时且无法扩展。相反,您可以实现 client 对象来获取并反序列化 JSON。
+
+ 打开
+
+ 将
+
+ 请注意,您需要将 ContentNegotiation 和 kotlinx.serialization 插件安装到 插件中,方式与在服务器上相同。
+
+ 在
+
+ 使用 Ktor client 或类似库测试服务非常方便,但从质量保证 (QA) 的角度来看,它也有一个缺点。服务器由于不直接处理 JSON,无法确定其关于 JSON 结构的假设是否正确。 +
++ 例如,此类假设包括: +
+array(数组)中,而实际上使用了 object(对象)。numbers(数字),而实际上是 strings(字符串)。+ 如果您的服务旨在供多个客户端使用,那么对 JSON 结构有信心至关重要。为此,请使用 Ktor Client 从服务器检索文本,然后使用 JSONPath 库分析此内容。
+在您的
+ dependencies 块中添加 JSONPath 库:
+
+ 导航至
+
+ 打开
+
+ JsonPath 查询的工作原理如下: +
+$[*].name 表示“将文档视为数组并返回每个条目的 name 属性值”。
+ $[?(@.priority == '$priority')].name 表示“返回数组中优先级等于所提供值的每个条目的 name 属性值”。
+ + 您可以使用此类查询来确认您对返回 JSON 的理解。当您进行代码重构和服务重新部署时,即使序列化中的任何修改不会破坏当前框架的反序列化,它们也会被识别出来。这让您能够放心地重新发布公开可用的 API。 +
++ 恭喜!您现在已完成为任务管理器应用程序创建 RESTful API 服务,并学习了使用 Ktor Client 和 JsonPath 进行单元测试的细节与要点。
+
+ 继续阅读
+
+ 代码示例: + + %example_name% + +
+
+ 使用的插件:
+ 在本教程中,您将学习如何使用 Kotlin 结合 Ktor 和 + Thymeleaf 模板构建一个交互式网站。 +
+
+ 在
+ 出于多种原因,您可能希望将所有实现保留在服务器上,并且只向客户端发送标记,例如: +
+
+ Ktor 通过集成
+ 您可以独立学习本教程,但我们强烈建议您先完成
+
我们建议您安装 IntelliJ + IDEA,但您也可以使用其他自选的 IDE。 +
+
+ 在本教程中,您将把在
+ 虽然您可以手动将这些插件添加到现有项目中,但生成一个新项目并逐步合并上一篇教程中的代码会更容易。我们将全程提供所有必要的代码,因此您不需要手头备有之前的项目。 +
++ 导航至 + Ktor Project Generator。 +
+
+ 在
+
+
在下一个屏幕中,通过点击
+
+
+ 添加插件后,您将看到项目设置下方列出的所有三个插件。
+
+
+ 点击
+
+ 在
+ enum 来表示优先级,以及一个 data class 来表示任务:
+
+ 再一次地,您需要创建 Task 对象,并以可以显示的形式将其发送给客户端。
+
+ 您可能还记得: +
+kotlinx.serialization 库中的 Serializable 类型注解了 Task 类。
+ + 在这种情况下,目标是创建一个服务器页面,将任务内容写入浏览器。 +
+
+ 在 .configureRouting() 函数中,按如下所示为 /tasks 添加一个路由:
+
+ 当服务器收到对 /tasks 的请求时,它会创建一个任务列表,然后将其传递给 Thymeleaf 模板。ThymeleafContent 类型接收要触发的模板名称,以及一个要在页面上访问的值表。
+
您应该看到以下 .configureThymeleaf 函数:
+ 在 Thymeleaf 插件的初始化过程中,Ktor 会在
+
+ 在这种情况下,名称 all-tasks 映射到路径
+ src/main/resources/templates/thymeleaf/all-tasks.html
+
打开
+
在 IntelliJ IDEA 中,点击运行按钮
+ ()
+ 以启动应用程序。
+ 在浏览器中导航至 http://0.0.0.0:8080/tasks。您应该会看到显示在表格中的所有当前任务,如下所示: +
+
+ + 与所有服务器页面框架一样,Thymeleaf 模板将静态内容(发送到浏览器)与动态内容(在服务器上执行)混合在一起。如果您选择了其他框架,例如 Freemarker,您也可以使用稍有不同的语法提供相同的功能。 +
+既然您已经熟悉了请求服务器页面的过程,请继续将之前教程中的功能转移到本教程中。
+因为您包含了
+
+ 这意味着,例如,对 /static/index.html 的请求将由以下路径提供内容:
+
src/main/resources/static/index.html
+ + 由于此文件已经是生成的项目的一部分,您可以将其用作您希望添加的功能的主页。 +
+
+ 打开
+
+ 在 IntelliJ IDEA 中,点击重新运行按钮 () 以重新启动应用程序。
+
+ 在浏览器中导航至 http://localhost:8080/static/index.html。您应该会看到一个链接按钮和三个 HTML 表单,允许您查看、筛选和创建任务: +
+
+
+ 请注意,当您按 name 或 priority 筛选任务时,您是在通过 GET 请求提交 HTML 表单。这意味着参数会被添加到 URL 之后的查询字符串中。
+
+ 例如,如果您搜索 Medium 优先级的任务,发送到服务器的请求如下所示:
+
http://localhost:8080/tasks/byPriority?priority=Medium
+ + 任务的仓库可以保持与上一个教程中的完全一致。 +
+
+ 在
+
+ 既然已经创建了仓库,您就可以实现 GET 请求的路由了。 +
+
+ 将当前版本的 .configureRouting() 替换为以下实现:
+
+ 上述代码可以概括如下: +
+/tasks 的 GET 请求中,服务器从仓库中检索所有任务,并使用
+ /tasks/byName 的 GET 请求中,服务器从 queryString 中检索参数 name,找到匹配的任务,并使用
+ /tasks/byPriority 的 GET 请求中,服务器从 queryString 中检索参数 priority,找到匹配的任务,并使用
+ 为了让所有这些正常工作,您需要添加额外的模板。
+
+ 打开
+
在同一个文件夹中,创建一个名为
+
+ 打开
+
+ 接下来,您将向 /tasks 添加一个 POST 请求处理程序,以执行以下操作:
+
+ 在 .configureRouting() 方法中添加以下 post 请求路由:
+
+ 在 IntelliJ IDEA 中,点击重新运行按钮 () 以重新启动应用程序。
+
+ 在
+
+ 点击
+
+ + 恭喜!您现在已完成将任务管理器重新构建为 Web 应用程序,并学习了如何使用 Thymeleaf 模板。
+
+ 继续阅读
+ 代码示例: + + %example_name% + +
+
+ 使用的插件:
+ 本文将指导您如何在 Kotlin 中使用 Ktor 创建 WebSocket 应用程序。它基于
本文将教您如何执行以下操作:
+您可以独立完成本教程,但我们建议您先完成
+
我们建议您安装 IntelliJ IDEA,但您也可以使用其他您喜欢的 IDE。 +
+
+ 在本教程中,您将通过添加通过 WebSocket 连接与客户端交换 Task 对象的功能,扩展在
+ 导航至 + Ktor 项目生成器。 +
+在
+
+
+ 在插件部分搜索并通过点击
+
+
+
+ 添加插件后,它们将显示在插件部分的右上角。 +
+然后您将看到将添加到项目中的所有插件列表:
+
+
+ 点击
+
下载完成后,在 IntelliJ IDEA 中打开您的项目并按照以下步骤操作:
+
+ 在
+
+ 打开
+ enum 来表示优先级,以及一个 data class 来表示任务:
+
+ 请注意,Task 类使用了来自 kotlinx.serialization 库的 Serializable 注解。这意味着实例可以转换为 JSON 以及从 JSON 转换,从而允许通过网络传输其内容。
+
+ 因为您包含了 WebSockets 插件,生成器已经在
+ webSocket 路由。
+
.configureWebsockets() 函数替换为以下内容:
+ contentConverter 属性,使插件能够通过 kotlinx.serialization 库对发送和接收的对象进行序列化。
+
+ 打开
+ Application.configureRouting() 函数替换为下面的实现:
+
/tasks。
+
+ 出于演示目的,在发送任务之间引入了一秒钟的延迟。这允许您观察任务在客户端中逐步出现的过程。如果没有这个延迟,该示例看起来将与之前文章中开发的
+ 此迭代的最后一步是为此端点创建一个客户端。因为您包含了
+
+ 打开
+
+ 该页面使用了所有现代浏览器中都可用的 WebSocket 类型。您在 JavaScript 中创建此对象,并将端点的 URL 传递到构造函数中。随后,您为 onopen、onclose 和 onmessage 事件附加事件处理程序。在触发 onmessage 事件时,您使用 document 对象的方法向表格追加一行。
+
在 IntelliJ IDEA 中,点击运行按钮
+ ()
+ 以启动应用程序。
+ 导航至 http://0.0.0.0:8080/static/index.html。您应该会看到一个带有一个按钮的表单和一个空表格: +
+
+
+ 当您点击表单时,任务会从服务器加载,并以每秒一个的速度出现。因此,表格会被增量填充。您还可以通过打开浏览器
+ + 至此,服务的表现符合预期。WebSocket 连接已打开,项目已发送到客户端,然后连接关闭。底层网络中存在很多复杂性,但 Ktor 默认处理了所有这些复杂性。 +
++ 在进行下一次迭代之前,回顾一下 WebSockets 的一些基础知识可能会有所帮助。如果您已经熟悉 WebSockets,可以继续 改进服务的设计。 +
++ 在之前的教程中,您的客户端发送 HTTP 请求并接收 HTTP 响应。这种模式运行良好,使互联网具备了可扩展性和弹性。 +
+然而,它不适用于以下场景:
++ 这些场景的示例包括股票交易、购买电影和音乐会门票、在线拍卖出价以及社交媒体中的聊天功能。WebSockets 的开发就是为了处理这些情况。 +
+
+ WebSocket 连接是建立在 TCP 之上的,可以持续很长时间。该连接提供
+ WebSocket API 定义了四个事件(open、message、close 和 error)和两个操作(send 和 close)。如何访问此功能可能因不同的语言和库而异。例如,在 Kotlin 中,您可以将传入消息序列作为 Flow 来消费。
+
接下来,您将重构现有代码,为更高级的示例腾出空间。
+
+ 在
+
+ 打开
+ TaskRepository 类型:
+
您可能还记得之前教程中的这段代码。
+
+ 您现在可以通过利用 TaskRepository 来简化 Application.configureRouting() 中的路由:
+
+ 为了展示 WebSockets 的强大功能,您将创建一个新端点,其中: +
+
+ 在
+ .configureRouting() 方法替换为下面的实现:
+
通过这段代码,您完成了以下工作:
+routing {} 块中,您创建了一个线程安全的 session 对象列表,以跟踪所有客户端。
+ /tasks2 的新端点。当客户端连接到此端点时,相应的 session 对象将被添加到列表中。然后服务器进入无限循环,等待接收新任务。收到新任务后,服务器将其存储在仓库中,并将副本发送给所有客户端(包括当前客户端)。
+
+ 为了测试此功能,您将创建一个扩展
+ 在
+
+ 打开
+
+ 这个新页面引入了一个 HTML 表单,用户可以在其中输入新任务的信息。提交表单后,将调用 sendTaskToServer() 事件处理程序。这将构建一个包含表单数据的 JavaScript 对象,并使用 WebSocket 对象的 .send() 方法将其发送到服务器。
+
+ 在 IntelliJ IDEA 中,点击重新运行按钮 () 以重启应用程序。
+
要测试此功能,请并排打开两个浏览器,并按照以下步骤操作。
+
+
+ 为了简化您的 QA 流程并使其快速、可复现且无需人工干预,您可以使用 Ktor 内置的
+ 将以下依赖项添加到
+
+
在 IntelliJ IDEA 中,点击编辑器右侧的 Gradle 通知图标
+ ()
+ 以加载 Gradle 更改。
+ 导航至
+
+ 将生成的测试类替换为以下实现: +
++ 通过此设置,您可以: +
+Tasks 列表。
+ client 对象的 .webSocket 函数向 /tasks 发送请求。
+ Flow 消费,并将其增量添加到列表中。
+ expectedTasks 与 actualTasks 进行比较。
+ + 做得好!通过将 WebSocket 通信和 Ktor Client 的自动化测试结合起来,您已经显著增强了任务管理器服务。 +
+
+ 继续阅读
+ 在本主题中,我们将向您展示如何向现有的 Gradle/Maven 项目中添加 Ktor Server 所需的依赖项。 +
++ 在添加 Ktor 依赖项之前,您需要为该项目配置仓库: +
+
+
+ Ktor 的生产版本可在 Maven 中央仓库中获取。 + 您可以按如下方式在构建脚本中声明此仓库: +
+
+ 您不需要在
+
+ 要访问 Ktor 的 EAP 版本,您需要引用 Space 仓库: +
++ 请注意,Ktor EAP 可能需要 Kotlin 开发仓库: +
++ 每个 Ktor 应用程序至少需要以下依赖项: +
+
+ ktor-server-core:包含 Ktor 核心功能。
+
+ 一个ktor-server-netty)的依赖项。
+
+ 针对不同的平台,Ktor 提供了带有后缀(如 -jvm)的平台特定构件,例如 ktor-server-core-jvm 或 ktor-server-netty-jvm。
+ 请注意,Gradle 会解析适用于给定平台的构件,而 Maven 则不支持此功能。
+ 这意味着对于 Maven,您需要手动添加平台特定后缀。
+ 一个基础 Ktor 应用程序的 dependencies 块可能如下所示:
+
+ Ktor 使用 SLF4J API 作为各种日志框架(例如 Logback 或 Log4j)的门面,并允许您记录应用程序事件。 + 要了解如何添加所需的构件,请参阅添加记录器依赖项。 +
+
+ 扩展 Ktor 功能的
+ 应用 Ktor Gradle 插件会隐式添加 Ktor BOM 依赖项,并允许您确保所有 Ktor 依赖项的版本一致。在这种情况下,在依赖 Ktor 构件时,您不再需要指定版本: +
++ 您还可以通过使用发布的版本目录来集中管理 Ktor 依赖项声明。 + 此方法具有以下优点: +
+
+ 要声明目录,请在
+ 然后,您可以通过引用目录名称在模块的
+ 使用 Gradle/Maven
+ 如果您使用 embeddedServer,请按如下方式指定主类: +
++ 如果您使用 EngineMain,则需要将其配置为主类。 + 对于 Netty,它将如下所示: +
++ 如果您打算将应用程序打包为 Fat JAR,那么在配置相应插件时,您还需要考虑创建服务器的方式。 + 请通过以下主题了解更多信息: +
+
+
+
+ Ktor 提供了一种专门针对开发的特殊模式。此模式启用了以下功能: +
++ 请注意,开发模式会影响性能,不应在生产环境中使用。 +
++ 您可以通过不同方式启用开发模式:在应用程序配置文件中、使用专用系统属性或环境变量。 +
+
+ 要在development 选项设置为 true:
+
+
+ 要在使用 IntelliJ IDEA 运行应用程序时开启开发模式,请将带有 -D 标志的 io.ktor.development 传递给 VM 选项:
+
+ 如果您使用
+ 在您的 ktor 块:
+
+ 通过传递 Gradle CLI 标志来为单次运行启用开发模式: +
+
+ 您也可以使用 -ea 标志来启用开发模式。
+ 请注意,使用 -D 标志传递的 io.ktor.development 系统属性的优先级高于 -ea。
+
+ 要为 原生客户端 启用开发模式,请使用 io.ktor.development 环境变量。
+
+
+ Ktor這個名稱源自縮寫ctor(建構函式),並將第一個字母替換為代表Kotlin的「K」。
+
+ CIO代表
+
+ 請確保在建置指令碼中加入了相對應的
+ 如果您正在執行EngineMain,它將會被自動處理。
+ 否則,您需要手動處理。
+ 您可以使用JVM提供的Runtime.getRuntime().addShutdownHook設施。
+
+ 如果代理伺服器提供了正確的標頭,且已安裝call.request.origin屬性會提供關於原始呼叫者(代理伺服器)的連線資訊。
+
+ 您可以從jetbrains.space獲取Ktor每晚建置版本。
+ 請從早期體驗計劃了解更多資訊。
+
+ 您可以使用Server回應標頭,例如:
+
+ Ktor提供了一種追蹤機制來協助排查路由決策問題。 + 請參閱追蹤路由章節。 +
+
+ 這表示您、或是某個外掛程式或攔截器已經呼叫過call.respond* 函式,而您正試圖再次呼叫它。
+
+ 請參閱
+ 這表示Ktor無法找到resources資料夾中存在設定檔,且該resources資料夾已被正確標記。
+ 建議使用Ktor專案產生器或IntelliJ IDEA Ultimate 的 Ktor 外掛程式來建立專案,以獲得一個可運作的專案基底。如需更多資訊,請參閱
+ 可以,已知Ktor伺服器和用戶端可在Android 5(API 21)或更高版本上運作,至少在使用Netty引擎時是如此。 +
+
+ CURL -I是CURL --head的別名,用於執行HEAD請求。
+ 預設情況下,Ktor不會為GET處理常式處理HEAD請求。
+ 若要啟用此功能,請安裝
+ 最可能的原因是您的後端位於反向代理或負載平衡器之後,而該中間設備正向您的後端發送一般的HTTP請求,因此Ktor後端內的HttpsRedirect外掛程式認為這是一個一般的HTTP請求,並以重定向作為回應。
+
+ 通常,反向代理會發送一些描述原始請求的標頭(例如原本是否為HTTPS或原始IP位址),而
+ Curl用戶端引擎需要安裝
+ curl程式庫。
+ 在Windows上,您可以考慮使用MinGW/MSYS2的curl二進位檔。
+
+ 按照MinGW/MSYS2中的說明安裝MinGW/MSYS2。 +
+
+ 使用以下指令安裝libcurl:
+
+ 如果您將MinGW/MSYS2安裝在預設位置,請將
+ PATH環境變數中。
+
+ NoTransformationFoundException + 代表無法為接收的主體找到合適的轉換,無法將結果型別轉換為用戶端預期的型別。 +
+
+ 檢查請求中的Accept標頭是否指定了所需的內容類型,以及伺服器回應中的Content-Type標頭是否與用戶端預期的型別相符。
+
+ 為您正在處理的特定內容類型註冊必要的內容轉換。 +
++ 您可以在用戶端使用ContentNegotiation + 外掛程式。 + 此外掛程式允許您指定如何針對不同的內容類型進行序列化和反序列化資料。 +
++ 確保您安裝了所有需要的外掛程式。可能缺少的功能包括: +
++ 程式碼範例: + + %example_name% + +
+
+ Ktor 包含一個多平台非同步 HTTP client,這讓你可以
+ 在本教學中,我們將向你展示如何建立第一個 Ktor 用戶端應用程式,該程式會傳送請求並列印出回應。 +
++ 在開始本教學之前,請先 + 安裝 IntelliJ IDEA Community 或 + Ultimate。 +
+
+ 你可以在現有專案中手動
+ 若要建立新的 Kotlin 專案,請 + 開啟 IntelliJ IDEA 並遵循以下步驟: +
+
+ 在歡迎畫面中,點擊
+ 或者,從主選單中選擇
+ 在
+
+ 在右側面板,指定以下設定: +
+
+
+
+
+
+
+
+ 點擊
+
+ 讓我們加入 Ktor 用戶端所需的相依性。 +
+
+ 開啟
+
+ 若要使用 EAP 版本的 Ktor,你需要加入 Space 儲存庫。 +
+
+ 開啟
+
ktor-client-core 是一個核心相依性,提供了主要的用戶端功能。
+ ktor-client-cio 是處理網路請求之
+ 點擊
+
+
+ 若要加入用戶端實作,請導覽至
+
+ 開啟
+
+ 在 Ktor 中,用戶端由 HttpClient + 類別表示。 +
+
+ 使用 HttpClient.get() 方法來HttpResponse 類別物件的形式接收。
+
+ 加入上述程式碼後,IDE 會針對 get() 函式顯示以下錯誤:
+
+
+ 若要修正此問題,你需要將 main() 函式設為暫停函式。
+
suspend 函式,請參閱 協同程式基礎。
+
+ 在 IntelliJ IDEA 中,點擊定義旁邊的紅色燈泡圖示,然後選擇
+
+
+ 使用 println() 函式來列印伺服器傳回的狀態碼,並使用 close() 函式來關閉串流並釋放與其相關的所有資源。
+
+ 若要執行你的應用程式,請導覽至
+
+ 在 IntelliJ IDEA 中,點擊 main() 函式旁邊的裝訂邊圖示,然後選擇
+
+
+ 你將在 IDE 底部的
+
+
+ 雖然伺服器回應了 200 OK 訊息,
+ 你也會看到一條錯誤訊息,指出 SLF4J 未能找到
+ StaticLoggerBinder 類別,並預設為無操作 (NOP) 記錄器實作。這實際上表示記錄功能已被停用。
+
+ 你現在已經有一個可運作的用戶端應用程式。然而,為了修正此警告並能夠透過記錄功能偵錯 HTTP 呼叫,還需要額外的步驟。 +
++ 因為 Ktor 在 JVM 上使用 SLF4J 抽象層進行記錄,若要啟用記錄,你需要 + 提供一個記錄架構,例如 + Logback。 +
+
+ 在
+
+ 開啟
+
+ 在 IntelliJ IDEA 中,點擊重新執行按鈕()以重新啟動應用程式。
+
+ 你應該不再看到該錯誤,而是在 IDE 底部的
+ 200 OK 訊息。
+
+ + 至此,你已經啟用了記錄功能。若要開始看到記錄內容,你需要加入記錄配置。 +
+導覽至
+
+ 在 IntelliJ IDEA 中,點擊重新執行按鈕()以重新啟動應用程式。
+
+ 你現在應該能夠在
+
+
+ 為了更深入理解並擴充此配置,請探索如何
+
+ 程式碼範例: + + %example_name% + +
++ Server-Sent Events (SSE) 是一種允許伺服器透過 HTTP 連線持續將事件推送到用戶端的技術。當伺服器需要發送基於事件的更新而不需要用戶端重複輪詢伺服器時,這項技術特別有用。 +
++ Ktor 支援的 SSE 外掛程式提供了一種簡單的方法,用於在伺服器和用戶端之間建立單向連線。 +
+若要進一步了解用於伺服器端支援的 SSE 外掛程式,請參閱
+
+ SSE 僅需要
+ 要安裝 SSE 外掛程式,請將其傳遞給 用戶端配置區塊 內的 install 函式:
+
+ 您可以選擇性地在 install 區塊中,透過設定
+ SSEConfig
+ 類別支援的屬性來配置 SSE 外掛程式。
+
+ 要啟用自動重新連線,請將
+ maxReconnectionAttempts 設定為大於 0 的值。您也可以使用 reconnectionTime 來配置兩次嘗試之間的延遲:
+
+ 如果與伺服器的連線中斷,用戶端將在嘗試重新連線之前等待指定的
+ reconnectionTime。它最多會進行
+ 指定的 maxReconnectionAttempts 次嘗試來重新建立連線。
+
+ 在以下範例中,SSE 外掛程式已安裝到 HTTP 用戶端中,並配置為在傳入流中僅包含包含註解的事件,以及僅包含 retry 欄位的事件:
+
+ SSE 回應在本質上是流式的,這使得擷取完整內容主體並不切實際。您可以啟用診斷緩衝區,以便在 SSE 流失敗時安全地檢索回應主體。該緩衝區僅包含已經處理過的資料(不從網路重新讀取),旨在用於失敗情況下的記錄和錯誤分析。 +
++ 您也可以針對每次呼叫進行配置: +
+
+ SSEBufferPolicy 型別提供了幾種儲存已處理 SSE 資料的策略。這些策略控制了流中有多少內容保留在記憶體中,並在發生錯誤時可供使用。
+
Off(預設)LastLines(n)LastEventLastEvents(n)All
+ 發生失敗時,您可以使用 response?.bodyAsText() 存取緩衝區,而無需從網路重新讀取。
+
+ 用戶端的 SSE 工作階段由
+
+ ClientSSESession
+
+ 介面表示。此介面公開了允許您從伺服器接收伺服器傳送事件的 API。
+
HttpClient 允許您透過以下方式之一存取 SSE 工作階段:
sse()
+
+ 函式會建立 SSE 工作階段並允許您對其進行操作。
+ sseSession()
+
+ 函式允許您開啟 SSE 工作階段。
+ 要指定 URL 端點,您可以從兩個選項中進行選擇:
+urlString 參數將整個 URL 指定為字串。schema、host、port 和 path 參數來指定協定架構、網域名稱、連接埠號和路徑名稱。
+ ClientSSESession 和 ClientSSESessionWithDeserialization 執行個體僅在工作階段持續期間有效。當 serverSentEvents { ... } 區塊完成或連線關閉時,其作用域會自動取消。
+ 此外,還有以下參數可用於配置連線:
+reconnectionTimeshowCommentEventsshowRetryEventsretry 欄位的事件。
+ deserializeTypedServerSentEvent 的 data 欄位轉換為物件。如需更多資訊,請參閱 反序列化。
+
+ 在 Lambda 引數內,您可以存取
+ ClientSSESession
+ 內容。區塊內提供以下屬性:
+
callHttpClientCall。
+ incoming
+ 下面的範例建立了一個連接到 events 端點的新 SSE 工作階段,透過 incoming 屬性讀取事件,並列印接收到的
+ ServerSentEvent
+ 。
+
如需完整範例,請參閱 + client-sse。 +
++ SSE 外掛程式支援將伺服器傳送事件反序列化為型別安全的 Kotlin 物件。此功能在處理來自伺服器的結構化資料時特別有用。 +
+
+ 要啟用反序列化,請在 SSE 存取函式上使用 deserialize 參數提供自訂的反序列化函式,並使用
+
+ ClientSSESessionWithDeserialization
+
+ 類別來處理反序列化後的事件。
+
+ 這是一個使用 kotlinx.serialization 反序列化 JSON 資料的範例:
+
如需完整範例,請參閱 + client-sse。 +
+
+ 必要的相依性:io.ktor:ktor-client-websockets
+
+ 程式碼範例: + + %example_name% + +
+用於用戶端的 Websockets 外掛程式可讓您處理與伺服器交換訊息的 WebSocket 工作階段。
+並非所有引擎都支援 WebSockets。如需支援引擎的概覽,請參閱限制。
+若要了解伺服器端的 WebSocket 支援,請參閱
若要使用 WebSockets,您需要在建置指令碼中包含 %artifact_name% 構件:
若要安裝 WebSockets 外掛程式,請將其傳遞給 用戶端配置區塊內的 install 函式:
您可以選擇透過在 install 區塊中傳遞
+ WebSockets.Config 支援的屬性來配置外掛程式。
+
maxFrameSizeFrame (框架) 大小。
+ contentConverterpingIntervalMillisLong 格式指定 ping 之間的持續時間。
+ pingIntervalDuration 格式指定 ping 之間的持續時間。
+ pingInterval 與 pingIntervalMillis 屬性不適用於 OkHttp 引擎。若要設定 OkHttp 的 ping 間隔,您可以使用引擎配置:
+
+ 在以下範例中,WebSockets 外掛程式配置了 20 秒(20_000 毫秒)的 ping 間隔,以自動發送 ping 框架並保持 WebSocket 連線:
+
用戶端的 WebSocket 工作階段由 + DefaultClientWebSocketSession + 介面表示。此介面公開了可讓您發送與接收 WebSocket 框架以及關閉工作階段的 API。 +
+
+ HttpClient 提供兩種主要方式來存取 WebSocket 工作階段:
+
webSocket()
+ 函式接受 DefaultClientWebSocketSession 作為區塊引數。
DefaultClientWebSocketSession 執行個體,並允許您在 runBlocking 或 launch 作用域之外存取工作階段。
+ 在函式區塊內,您可以為指定的路徑定義處理常式。區塊內可以使用以下函式與屬性:
+send()send() 函式向伺服器發送文字內容。
+ outgoingoutgoing 屬性存取用於發送 WebSocket 框架的頻道。框架由 Frame 類別表示。
+ incomingincoming 屬性存取用於接收 WebSocket 框架的頻道。框架由 Frame 類別表示。
+ close()close() 函式發送帶有指定原因的關閉框架。
+ + 您可以檢查 WebSocket 框架的類型並進行相應處理。一些常見的框架類型包括: +
+Frame.Text 表示文字框架。使用
+ Frame.Text.readText() 讀取其內容。
+ Frame.Binary 表示二進位框架。使用 Frame.Binary.readBytes()
+ 讀取其內容。
+ Frame.Close 表示關閉框架。使用 Frame.Close.readReason()
+ 取得工作階段關閉的原因。
+ 下面的範例建立了 echo WebSocket 端點,並展示如何向伺服器發送和接收訊息。
如需完整範例,請參閱 + client-websockets。 +
+
+
+
在本主題中,我們將向您展示如何在 Docker Compose 下執行伺服器端 Ktor 應用程式。我們將使用在
+ 在 配置資料庫連線 教學中建立的專案使用硬編碼屬性來建立資料庫連線。
+
+ 讓我們將 PostgreSQL 資料庫的連線設定擷取到
開啟
+ ktor 群組之外新增 storage 群組,如下所示:
+
這些設定稍後將在
+
+ 開啟
+ configureDatabases() 函式以從配置檔案載入儲存設定:
+
+ configureDatabases() 函式現在接受 ApplicationConfig 並使用 config.property 來載入自訂設定。
+
+ 開啟
+ environment.config 傳遞給 configureDatabases(),以便在應用程式啟動時載入連線設定:
+
為了在 Docker 上執行,應用程式需要將所有必要的檔案部署到容器中。根據您使用的建置系統,有不同的外掛程式可以完成此操作:
+在我們的範例中,Ktor 外掛程式已套用於
+
+ 要將應用程式 Docker 化,請在專案的根目錄中建立一個新的
+
+ 此範例使用 Amazon Corretto Docker 映像,但您可以將其替換為任何其他合適的替代方案,例如: +
+在專案的根目錄中,建立一個新的
+
web 服務用於執行封裝在 映像 內的 Ktor 應用程式。
+ db 服務使用 postgres 映像建立
+ ktor_tutorial_db 資料庫以儲存任務。
+ + 執行以下指令以建立包含 Ktor 應用程式的 fat JAR: +
+
+ 使用 docker compose up 指令來建置映像並啟動容器:
+
+ 導覽至 http://localhost:8080/static/index.html + 以開啟 Web 應用程式。您應該會看到工作管理員用戶端頁面,其中顯示了三個用於篩選和新增新任務的表單,以及一個任務表格。 +
+
+ + 程式碼範例: + + %example_name% + +
+
+ 使用的外掛程式:
+ 在本文中,您將學習如何使用 Kotlin 開發一個能在 Android、iOS、Web 和桌面平台上執行的全端應用程式,同時利用 Ktor 實現無縫資料處理。 +
+在本教學結束時,您將瞭解如何執行以下操作:
+
+ 在之前的教學中,我們使用任務管理員(Task Manager)範例來
+
+ 您將建立一個針對 Android、iOS、Web 和桌面平台的用戶端,並使用 Ktor 服務來獲取要顯示的資料。在可能的情況下,您將在用戶端和伺服器之間共享資料型別,從而加快開發速度並減少潛在錯誤。 +
++ 與之前的文章一樣,您將使用 IntelliJ IDEA 作為 IDE。要安裝和配置您的環境,請參閱 + + Kotlin Multiplatform 快速入門指南 + + 。 +
++ 如果這是您第一次使用 Compose Multiplatform,我們建議您在開始本教學之前先完成 + + Compose Multiplatform 入門 + + 教學。為了降低任務的複雜性,您可以專注於單一用戶端平台。例如,如果您從未使用過 iOS,那麼專注於桌面或 Android 開發可能是明智的。 +
++ 不使用 Ktor 專案產生器,而是使用 IntelliJ IDEA 中的 Kotlin Multiplatform 專案精靈。它將建立一個基礎的多平台專案,您可以透過用戶端和服務對其進行擴展。用戶端可以使用原生 UI 連結庫(例如 SwiftUI),但在本教學中,您將使用 Compose Multiplatform 為所有平台建立共用 UI。 +
+
+ 選擇
+
+ 如果您使用的是 Mac,也請選擇
+
+
+ 點擊
+
+
+
+ 導航至 http://0.0.0.0:8080/ 以開啟應用程式。您應該會在瀏覽器中看到來自 Ktor 的訊息。
+
+
+
+
+
+ 如果您查看
+ sayHello() 函式的呼叫:
+
+ sayHello() 函式定義在
+
+ 開啟 sayHello() 函式:
+
+
+
+ 例如,在 Greeting 型別中,目前平台的名稱是透過平台特定的 API 獲取的,這是透過 expect 和 actual 宣告 實現的。
+
+ 在
+ getPlatform() 函式使用 expect 關鍵字宣告:
+
+ 然後,每個目標平台提供 getPlatform() 函式的 actual 宣告,如下所示:
+
+ 您可以透過執行目標的執行配置來執行用戶端應用程式。要在 iOS 模擬器上執行應用程式,請按照以下步驟操作: +
+
+
+ 當您執行 iOS 應用程式時,它會在後台使用 Xcode 進行構建並在 iOS 模擬器中啟動。該應用程式顯示一個按鈕,點擊時會切換圖片。
+
+
+ 第一次按下按鈕時,目前平台的詳細資訊會新增到按鈕文字中。實現此功能的程式碼位於
+
+ 這是一個可組合(composable)函式,您稍後將在本文中對其進行修改。目前,唯一重要的是它顯示了一個 UI 並使用了共享的 Greeting 型別,而該型別又使用了實作通用 Platform 介面的平台特定類別。
+
+ 既然您已經瞭解了產生專案的結構,就可以逐步新增任務管理員功能。 +
++ 首先,新增模型型別並確保用戶端和伺服器都可以訪問它們。 +
+kotlinx.serialization 相依性:
+
+ 導航至
+
+ 在同一個檔案中,為
+
+ 新增一個列舉來表示優先級(priorities),以及一個類別來表示任務。
+ Task
+ 類別使用了來自
+ kotlinx.serialization
+ 連結庫的 Serializable 註解:
+
+ 下一階段是為任務管理員建立伺服器端實作。 +
+
+ 在此封裝中,建立一個新的
+
+ 在同一個封裝中,建立一個名為
+
+ 導航至
+
+ 此實作與之前教學中的實作非常相似,不同之處在於現在為了簡化,我們將所有路由程式碼都放在 Application.module() 函式中。
+
+ 輸入此程式碼並新增匯入後,您會發現多個編譯器錯誤,因為程式碼使用了多個需要作為相依性包含的 Ktor 外掛程式,包括用於與 Web 用戶端互動的
+ 開啟伺服器模組組建檔案(
+
ContentNegotiation 型別和 json() 函式的匯入工作正常。
+ + 為了讓您的用戶端能夠訪問伺服器,您需要包含 Ktor 用戶端。這涉及三種類型的相依性: +
+
+ 完成此操作後,您可以新增一個 TaskApi 型別,作為您的用戶端對 Ktor 用戶端的薄包裝函式。
+
+ 在新封裝中,建立一個新的
+
+ 將 1.2.3.4 替換為您目前電腦的 IP 地址。您將無法從在 Android 虛擬裝置或 iOS 模擬器上執行的程式碼中呼叫 0.0.0.0 或 localhost。
+
尋找您的 IP 地址:
+
+ 由於行動模擬器無法訪問 localhost,您需要電腦的實際 IP 地址。要尋找您的 IP 地址,請執行以下命令之一:
+
ifconfig | grep "inet " | grep -v 127.0.0.1hostname -I | awk '{print $1}'ipconfig 並尋找 "IPv4 Address"
+ 在同一個
+
+ 導航至
+ TaskApi 型別從伺服器獲取任務列表,然後在列中顯示每個任務的名稱:
+
+ 在伺服器執行的同時,透過執行
+ 點擊
+
+
+ 在 Android 平台上,您需要明確地授予應用程式網路權限,並允許其以明文形式發送和接收資料。要啟用這些權限,請開啟
+
+ 使用
+
+ 對於桌面用戶端,您將為容器視窗分配尺寸和標題。開啟檔案
+ title 並設定 state 屬性來修改程式碼:
+
+ 使用
+
+ 使用以下執行配置之一執行 Web 用戶端: +
+
+ + 用戶端現在正在與伺服器通信,但這顯然稱不上是一個美觀的 UI。 +
+
+ 開啟位於
+ App 替換為下面的 App 和 TaskCard 可組合項:
+
+ 透過此實作,您的用戶端現在具備了一些基本功能。 +
+
+ 透過使用 LaunchedEffect 型別,所有任務都會在啟動時載入,而 LazyColumn 可組合項允許使用者捲動任務列表。
+
+ 最後,建立了一個單獨的 TaskCard 可組合項,它轉而使用 Card 來顯示每個 Task 的詳細資訊。還新增了用於刪除和更新任務的按鈕。
+
+ 重新執行用戶端應用程式 — 例如 Android 應用程式。您現在可以捲動任務、查看其詳細資訊並將其刪除:
+
+
+ 為了完成用戶端,請加入允許更新任務詳細資訊的功能。 +
+
+ 新增 UpdateTaskDialog 可組合項和必要的匯入,如下所示:
+
+ 這是一個使用對話方塊顯示 Task 詳細資訊的可組合項。description 和 priority 被放置在 TextField 可組合項中,以便它們可以被更新。當使用者按下更新按鈕時,它會觸發 onConfirm() 回呼。
+
+ 更新同一個檔案中的 App 可組合項:
+
+ 您正在儲存一個額外的狀態,即當前選取的任務。如果此值不為 null,那麼我們將調用我們的 UpdateTaskDialog 可組合項,並將 onConfirm() 回呼設定為使用 TaskApi 向伺服器發送 POST 請求。
+
+ 最後,當您建立 TaskCard 可組合項時,您使用 onUpdate() 回呼來設定 currentTask 狀態變數。
+
+ + 在本文中,您已在 Kotlin Multiplatform 應用程式的內容中使用了 Ktor。您現在可以建立一個包含多個服務和用戶端,並針對一系列不同平台的專案。 +
+
+ 正如您所看到的,構建功能時無需任何程式碼重複或冗餘。專案所有層級所需的型別都可以放置在
+
+ 這種開發必然需要用戶端和伺服器技術的知識。但您可以使用 Kotlin Multiplatform 連結庫和 Compose Multiplatform 來最大限度地減少您需要學習的新內容。即使您最初只專注於單一平台,隨著對應用程式需求的成長,您也可以輕鬆新增其他平台。 +
++ 程式碼範例: + migrating-express + migrating-express-ktor +
++ 在本指南中,我們將探討在基本情境下如何將 Express 應用程式遷移至 Ktor: + 從產生應用程式與撰寫您的第一個應用程式,到建立用於擴充應用程式功能的中介軟體。 +
+|
+ |
+
+
+ 您可以使用 |
+
|
+ |
+
+ + Ktor 提供以下幾種方式來產生應用程式骨架: + +
+Ktor 專案產生器 (Ktor Project Generator) — 使用網頁版產生器。 + +
+
+ Ktor CLI 工具
+ — 透過命令列介面使用 + + Yeoman 產生器 + + — 以互動方式配置專案設定並選取所需的外掛程式: + ++IntelliJ IDEA Ultimate — 使用內建的 Ktor 專案精靈。 + +
+ 如需詳細指示,請參閱 |
+
+ 在本節中,我們將探討如何建立最簡單的伺服器應用程式,該程式接收 GET 請求並以預定義的純文字進行回應。
+
|
+ |
+
+
+ 下方的範例顯示了啟動伺服器並監聽通訊埠 + 如需完整範例,請參閱 + 1_hello + 專案。 + + |
+
|
+ |
+
+ + 在 Ktor 中,您可以使用 embeddedServer + 函式在程式碼中配置伺服器參數並快速執行應用程式。 + ++ 如需完整範例,請參閱 + 1_hello + 專案。 + ++ 您也可以在採用 HOCON 或 YAML 格式的 外部配置檔案 中指定伺服器設定。 + + |
+
+ 請注意,上述 Express 應用程式會加入
+ 若要在 Ktor 的每個回應中加入預設的
+ 在本節中,我們將探討如何在 Express 與 Ktor 中提供影像、CSS 檔案與 JavaScript 檔案等靜態檔案。
+ 假設我們有一個
|
+ |
+
+
+ 在 Express 中,將資料夾名稱傳遞給 + 如需完整範例,請參閱 + 2_static + 專案。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,使用 + 如需完整範例,請參閱 2_static + 專案。 + + |
+
+ 提供靜態內容時,Express 會加入數個回應標頭,內容可能如下所示: +
++ 要在 Ktor 中管理這些標頭,您需要安裝以下外掛程式: +
+
+
+
+
+ GET、POST 等)與路徑定義。
+ 下方的範例展示如何處理傳送到 GET 與 POST 請求。
+
|
+ |
+
+ + 如需完整範例,請參閱 + 3_router + 專案。 + + |
+
|
+ |
+
+
+ 請參閱 接收請求 以了解如何接收 + 如需完整範例,請參閱 + 3_router + 專案。 + + |
+
+ 以下範例示範如何依路徑分組路由處理常式。 +
+|
+ |
+
+
+ 在 Express 中,您可以使用 + 如需完整範例,請參閱 + 3_router + 專案。 + + |
+
|
+ |
+
+
+ Ktor 提供 + 如需完整範例,請參閱 + 3_router + 專案。 + + |
+
+ 這兩個架構都允許您將相關路由分組在單個檔案中。 +
+|
+ |
+
+
+ Express 提供 + 如需完整範例,請參閱 + 3_router + 專案。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,常見的模式是在 + 如需完整範例,請參閱 + 3_router + 專案。 + + |
+
+ 除了將 URL 路徑指定為字串外,Ktor 還包含實作
+ 本節將展示如何存取路由參數與查詢參數。 +
++ 路由(或路徑)參數是具名的 URL 片段,用於擷取在 URL 中該位置指定的值。 +
+|
+ |
+
+
+ 要在 Express 中存取路由參數,您可以使用 + 如需完整範例,請參閱 + 4_parameters + 專案。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,路由參數是使用 + 如需完整範例,請參閱 + 4_parameters + 專案。 + + |
+
+ 下表比較了如何存取查詢字串的參數。 +
+|
+ |
+
+
+ 要在 Express 中存取路由參數,您可以使用 + 如需完整範例,請參閱 + 4_parameters + 專案。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,路由參數是使用 + 如需完整範例,請參閱 + 4_parameters + 專案。 + + |
+
+ 在之前的章節中,我們已經看過如何以純文字內容進行回應。 + 讓我們來看看如何傳送 JSON、檔案與重新導向回應。 +
+|
+ |
+
+
+ 要在 Express 中傳送具有適當內容類型的 JSON 回應,請呼叫 + 如需完整範例,請參閱 + 5_send_response + 專案。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,您需要安裝
+ 要將資料序列化為 JSON,您需要建立一個帶有
+ 然後,您可以使用 + 如需完整範例,請參閱 + 5_send_response + 專案。 + + |
+
|
+ |
+
+
+ 要在 Express 中以檔案回應,請使用 + 如需完整範例,請參閱 + 5_send_response + 專案。 + + |
+
|
+ |
+
+
+ Ktor 提供 + 如需完整範例,請參閱 + 5_send_response + 專案。 + + |
+
+ Express 應用程式在以檔案回應時,會加入
|
+ |
+
+
+ + 如需完整範例,請參閱 + 5_send_response + 專案。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,您需要手動配置 + 如需完整範例,請參閱 + 5_send_response + 專案。 + + |
+
|
+ |
+
+
+ 要在 Express 中產生重新導向回應,請呼叫 + 如需完整範例,請參閱 + 5_send_response + 專案。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,使用 + 如需完整範例,請參閱 + 5_send_response + 專案。 + + |
+
+ Express 與 Ktor 都能夠配合範本引擎來處理檢視 (views)。 +
+|
+ |
+
+
+ 假設我們在
+ 要以該範本回應,請呼叫 + 如需完整範例,請參閱 + 6_templates + 專案。 + + |
+
|
+ |
+
+
+ Ktor 支援數種 + 如需完整範例,請參閱 + 6_templates + 專案。 + + |
+
+ 本節將展示如何接收不同格式的請求主體。 +
+
+ 下方的 POST 請求向伺服器傳送文字資料:
+
+ 讓我們來看看如何在伺服器端將此請求的主體作為純文字接收。 +
+|
+ |
+
+
+ 要在 Express 中剖析傳入的請求主體,您需要加入
+ 在 + 如需完整範例,請參閱 + 7_receive_request + 專案。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,您可以使用 + 如需完整範例,請參閱 + 7_receive_request + 專案。 + + |
+
+ 在本節中,我們將探討如何接收 JSON 主體。
+ 下方的範例顯示了一個在其主體中帶有 JSON 物件的 POST 請求:
+
|
+ |
+
+
+ 要在 Express 中接收 JSON,請使用 + 如需完整範例,請參閱 + 7_receive_request + 專案。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,您需要安裝 + 要將接收到的資料還原序列化為物件,您需要建立一個資料類別: + +
+ 然後,使用接受此資料類別作為參數的 + 如需完整範例,請參閱 + 7_receive_request + 專案。 + + |
+
+ 現在讓我們來看看如何接收使用 POST 請求:
+
|
+ |
+
+
+ 與純文字和 JSON 同樣,Express 需要 + 如需完整範例,請參閱 + 7_receive_request + 專案。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,使用 + 如需完整範例,請參閱 + 7_receive_request + 專案。 + + |
+
+ 下一個使用案例是處理二進位資料。
+ 下方的請求將帶有
|
+ |
+
+
+ 要在 Express 中處理二進位資料,請將剖析器型別設定為 + 如需完整範例,請參閱 + 7_receive_request + 專案。 + + |
+
|
+ |
+
+
+ Ktor 提供 + 如需完整範例,請參閱 + 7_receive + request + 專案。 + + |
+
+ 在最後一節中,讓我們來看看如何處理 POST 請求使用
|
+ |
+
+
+ Express 需要個別的模組來剖析多部分資料。
+ 在下方的範例中,使用了 + 如需完整範例,請參閱 + 7_receive_request + 專案。 + + |
+
|
+ |
+
+
+ 在 Ktor 中,如果您需要接收作為多部分請求的一部分傳送的檔案,
+ 請呼叫 + 如需完整範例,請參閱 + 7_receive_request + 專案。 + + |
+
+ 最後我們要探討的是如何建立允許您擴充伺服器功能的中介軟體。 + 下方的範例展示如何使用 Express 與 Ktor 實作請求記錄。 +
+|
+ |
+
+
+ 在 Express 中,中介軟體是使用 + 如需完整範例,請參閱 + 8_middleware + 專案。 + + |
+
|
+ |
+
+
+ Ktor 允許您使用 + 如需完整範例,請參閱 + 8_middleware + 專案。 + + |
+
+ 本指南中還有許多未涵蓋的使用案例,
+ 如工作階段管理、授權、資料庫整合等。
+ 對於大多數功能,Ktor 提供了專用的外掛程式,
+ 可以安裝在應用程式中並根據需要進行配置。
+ 要繼續您的 Ktor 旅程,
+ 請造訪
+ 程式碼範例: + autoreload-engine-main, + autoreload-embedded-server +
+
+ 在開發過程中
+ 啟用開發模式 +
++ (選用) 配置監控路徑 +
++ 在變更時啟用重新編譯 +
+| 模組類型 | +<= 3.2 | +> 3.2 | +
| Lambda 初始設定式 | +❌ 不支援 | +❌ 不支援 | +
| 阻塞函式參考 (Blocking function reference) | +✅ 已支援 | +❌ 不支援 | +
| 掛起函式參考 (Suspend function reference) | +❌ 不支援 | +✅ 已支援 | +
| 組態參考 (Config reference) | +✅ 已支援 | +✅ 已支援 | +
+ 要使用自動重新載入,您需要先啟用
+ 開發模式。
+ 這取決於您
+ 如果您使用 EngineMain 來執行伺服器,請在 組態檔 中啟用開發模式。
+
+ 如果您使用 embeddedServer 執行伺服器,可以使用
+ io.ktor.development
+ 系統屬性。
+
+ 啟用開發模式後,Ktor 將會自動監控工作目錄中的輸出檔案。 + 如有需要,您可以透過指定 監控路徑 來縮小監控資料夾的範圍。 +
+
+ 當您 啟用 開發模式時,
+ Ktor 會開始監控工作目錄中的輸出檔案。
+ 例如,對於使用 Gradle 組建的
+ 監控路徑允許您縮小監控資料夾的範圍。
+ 為此,您可以指定監控路徑的一部分。
+ 例如,要監控 classes 作為監控路徑傳遞。
+ 根據您執行伺服器的方式,您可以透過以下方式指定監控路徑:
+
+ 在 watch 選項:
+
+ 您也可以指定多個監控路徑,例如: +
++ 您可以在此處找到完整的範例: autoreload-engine-main。 +
+
+ 如果您使用的是 embeddedServer,請將監控路徑作為 watchPaths 參數傳遞:
+
+ 完整範例請參閱 + + autoreload-embedded-server + + 。 +
+
+ 由於自動重新載入會偵測輸出檔案的變更,
+ 因此您需要重新組建專案。
+ 您可以在 IntelliJ IDEA 中手動執行此操作,或者
+ 使用 -t 命令列選項在 Gradle 中啟用持續建置執行。
+
+ 要在 IntelliJ IDEA 中手動重新組建專案,從主選單中選擇
+
+ 要使用 Gradle 自動重新組建專案,
+ 您可以在終端中執行帶有 -t 選項的 build 任務:
+
+ 要在重新載入專案時跳過執行測試,可以將 -x 選項傳遞給 build 任務:
+
+ Ktor 允許您直接在程式碼中配置各種伺服器參數,包括主機位址、port、
+ 使用 embeddedServer 時,您可以透過將所需的參數直接傳遞給該函式來配置伺服器。
+
+ embeddedServer
+
+ 函式接受用於配置伺服器的不同參數,包括
+ 在本節中,我們將查看幾個執行 embeddedServer 的不同範例,說明如何配置伺服器以發揮其優勢。
+
+ 下方的程式碼片段顯示了使用 Netty 引擎與 8080 port 的基本伺服器設定。
+
+ 請注意,您可以將 port 參數設定為 0 以在隨機 port 上執行伺服器。
+ embeddedServer 函式會回傳一個引擎執行個體,因此您可以使用
+
+ ApplicationEngine.resolvedConnectors
+
+ 函式在程式碼中獲取 port 值。
+
+ embeddedServer 函式允許您使用 configure 參數傳遞特定於引擎的選項。此參數包含所有引擎通用的選項,並由
+
+ ApplicationEngine.Configuration
+
+ 類別公開。
+
+ 下方的範例顯示如何使用 Netty 引擎配置伺服器。在 configure 區塊內,我們定義了一個 connector 來指定主機與 port,並自訂各種伺服器參數:
+
+ connectors.add() 方法定義了一個具有指定主機 (127.0.0.1) 與 port (8080) 的連接器。
+
除了這些選項之外,您還可以配置其他特定於引擎的屬性。
++ 特定於 Netty 的選項由 + + NettyApplicationEngine.Configuration + + 類別公開。 +
++ 特定於 Jetty 的選項由 + + JettyApplicationEngineBase.Configuration + + 類別公開。 +
+您可以在 + + configureServer + + 區塊內配置 Jetty 伺服器,該區塊提供了對 + Server + 執行個體的存取。 +
+
+ 使用 idleTimeout 屬性指定連線在關閉前可以保持閒置的時間長度。
+
特定於 CIO 的選項由 + + CIOApplicationEngine.Configuration + + 類別公開。 +
+如果您使用 Tomcat 作為引擎,可以使用 + + configureTomcat + + 屬性進行配置,該屬性提供了對 + Tomcat + 執行個體的存取。 +
++ 下方的範例顯示如何使用 + + ApplicationEngine.Configuration + + 類別代表的自訂配置,執行具有多個連接器端點的伺服器。 +
++ 如需完整範例,請參閱 + + embedded-server-multiple-connectors + 。 +
++ 您也可以使用自訂環境來 + + 提供 HTTPS 服務 + 。 +
+
+ Ktor 允許您使用命令列引數動態地配置 embeddedServer。這在需要在執行階段指定 port、主機或逾時等配置的情況下特別有用。
+
+ 為此,請使用 + + CommandLineConfig + + 類別將命令列引數解析為配置物件,並將其傳遞至配置區塊中: +
+
+ 在此範例中,來自 Application.Configuration 的
+
+ takeFrom()
+
+ 函式用於覆蓋引擎配置值,例如 port 和 host。
+
+ loadCommonConfiguration()
+
+ 函式則從根環境載入配置,例如逾時。
+
+ 要執行伺服器,請按以下方式指定引數: +
++ 程式碼範例: + + %example_name% + +
++ 在本教學中,您將學習如何建立、開啟並執行您的第一個 Ktor 伺服器專案。一旦啟動並執行,您可以完成一系列任務來熟悉 Ktor。 +
++ 這是引導您開始使用 Ktor 建置伺服器應用程式系列教學的第一部分。您可以獨立完成每個教學,但我們強烈建議您按照建議的順序進行: +
++ 建立新 Ktor 專案最快的方法之一是使用網頁版 Ktor 專案產生器。 +
++ 或者,您可以使用 IntelliJ IDEA Ultimate 專用的 Ktor 外掛程式或 Ktor CLI 工具來產生專案。 +
++ 若要使用 Ktor 專案產生器建立新專案,請按照以下步驟操作: +
+導覽至 Ktor 專案產生器。
+在
+
+
點擊
+
+
+ 提供以下設定: +
+
+
+
+
對於本教學,您可以保留這些設定的預設值。
+點擊
+
在下方您會發現一組可以新增到專案中的
就本教學而言,您目前不需要新增任何外掛程式。
+
+ 點擊
+
+
您的下載應該會自動開始。
+既然您已經產生了新專案,請繼續解包並執行您的 Ktor 專案。
++ 本節說明如何使用 IntelliJ IDEA Ultimate 的 Ktor 外掛程式進行專案設定。 +
++ 若要建立新的 Ktor 專案,請開啟 IntelliJ IDEA 並按照以下步驟操作: +
+
+ 在歡迎畫面,點擊
+ 或者,從主功能表選擇
+ 在
+
+ 在右側窗格中,您可以指定以下設定: +
+
+
+
+
+
+
+
+
+ 點擊
+
+ + 提供以下設定: +
+
+
+
+
就本教學而言,您可以保留這些設定的預設值。
+
+ 點擊
+
+
+ 在此頁面上,您可以選擇一組
就本教學而言,您目前不需要新增任何外掛程式。
+
+ 點擊
+
+ 既然您已建立了新專案,請繼續學習如何 開啟、探索並執行 該應用程式。 +
++ 本節說明如何使用 Ktor CLI 工具進行專案設定。 +
++ 若要建立新的 Ktor 專案,請開啟您偏好的終端機並按照以下步驟操作: +
+
+
+ (選填)您也可以透過編輯專案名稱下方的
+
+ 就本教學而言,您目前不需要新增任何外掛程式。
+
+ 或者,您可以透過選擇
+
+ 在本節中,您將學習如何從命令列解包、組建並執行專案。以下步驟假設: +
+如有必要,請修改名稱和路徑以符合您自己的設定。
+開啟您偏好的命令列工具並按照以下步驟操作:
+在終端機視窗中,導覽至您下載專案的資料夾:
+將 ZIP 封存檔解包到同名的資料夾中:
+您的目錄現在將包含 ZIP 封存檔和解包後的資料夾。
+從該目錄導覽進入新建立的資料夾:
+在 macOS 和 UNIX 系統上,您必須使 Gradle 輔助指令碼成為可執行檔,以便系統將其識別為可執行指令。為此,請使用 chmod 指令:
若要組建專案,請使用以下指令:
+當組建成功後,繼續下一個步驟以執行專案。
+若要執行專案,請使用以下指令:
+若要驗證專案是否正在執行,請在瀏覽器中開啟終端機輸出中顯示的 URL (http://0.0.0.0:8080)。 + 您應該會在瀏覽器中看到顯示 "Hello World!" 訊息:
+
+ 恭喜!您已成功啟動您的 Ktor 專案。
+如果您安裝了 IntelliJ IDEA,您可以輕鬆地從命令列開啟專案。 +
+
+ 確保您位於專案資料夾中,然後輸入 idea 指令,後跟一個句點來代表當前資料夾:
+
+ 或者,若要手動開啟專案,請啟動 IntelliJ IDEA。 +
+
+ 如果開啟了歡迎畫面,點擊
+
開啟專案後,您可以看到以下結構:
+
+
+ 若要檢視完整的版面配置,請點擊每個資料夾旁邊的展開箭頭,在
+ 應用程式原始碼位於
+
+ 專案名稱是在
+
+ 配置檔案和其他類型的內容位於
+
+ 若要在 IntelliJ IDEA 內執行專案:
+點擊右側提欄上的 Gradle 圖示 ()
+ 以開啟 Gradle 工具視窗。
在此工具視窗中,導覽至
+
+ 您的 Ktor 應用程式會在 IDE 底部的 執行工具視窗中啟動:
+
+ 先前在命令列上顯示的相同訊息現在將在
+
若要確認專案正在執行,請在指定的 URL + (http://0.0.0.0:8080) 開啟瀏覽器。
+您應該會再次在螢幕上看到顯示 "Hello World!" 訊息:
+
+
+ 您可以透過
+
+ 這些選項在 IntelliJ IDEA 執行工具視窗文件中有進一步說明。 +
+以下是一些您可能希望嘗試的額外任務:
++ 這些任務彼此獨立,但複雜度逐漸增加。按宣告的順序嘗試它們是循序漸進學習的最簡單方式。為了簡單起見並避免重複,下面的描述假設您正按順序嘗試任務。 +
++ 在需要編寫程式碼的地方,我們同時指定了程式碼和對應的匯入。IDE 可能會自動為您新增這些匯入。 +
+
+ 如果您選擇將配置儲存在外部的 YAML 或 HOCON 檔案中,在
+
port 值更改為您選擇的另一個數字,例如
+ 9292。
+ 點擊重新執行按鈕 ()
+ 以重新啟動應用程式。
要驗證您的應用程式是否在新的連接埠號碼下執行,您可以在瀏覽器中開啟新的 URL (http://0.0.0.0:9292) 或 + 在 IntelliJ IDEA 中建立新的 HTTP 請求檔案:
+
+ + 建立新的 Ktor 專案時,您可以選擇將配置儲存在程式碼中或外部的 YAML 或 HOCON 檔案中。 +
+
+ 如果您選擇了將配置儲存在程式碼中的選項,在
+
開啟
+
在 embeddedServer() 函式中,將 port 參數更改為您選擇的另一個數字,例如 9292。
點擊重新執行按鈕 ()
+ 以重新啟動應用程式。
要驗證您的應用程式是否在新的連接埠號碼下執行,您可以在瀏覽器中開啟新的 URL (http://0.0.0.0:9292),或 + 在 IntelliJ IDEA 中建立新的 HTTP 請求檔案:
+
+
+ 在
+
開啟
+
若要建立新端點,請插入如下所示的額外路由:
+/test1 URL 更改為您喜歡的任何內容。IDE 會自動為 ContentType 新增匯入:
點擊重新執行按鈕 ()
+ 以重新啟動應用程式。
在瀏覽器中請求新的 URL (http://0.0.0.0:9292/test1)。連接埠號碼取決於您是否完成了更改預設連接埠任務。您應該看到如下所示的輸出:
+
+ 如果您建立了 HTTP 請求檔案,也可以在那裡驗證新端點:
+###) 的行來分隔不同的請求。在
+
開啟
這一行的含義如下:
+staticResources() 使您的應用程式能夠提供標準的網站內容,例如 HTML 和 JavaScript 檔案。儘管這些內容可以在瀏覽器中執行,但從伺服器的角度來看,它們被視為靜態的。
+ /content 指定用於獲取此內容的路徑。
+ mycontent 是靜態內容所在的資料夾名稱。Ktor 將在 resources 目錄中尋找此資料夾。
+ 如果 IDE 沒有自動新增,請新增以下匯入。
+在
+
或者,選擇
將新目錄命名為 mycontent 並按下
+
右鍵點擊新建立的資料夾並點擊
+
將新檔案命名為
在新建的檔案頁面填入有效的 HTML,例如:
+點擊重新執行按鈕 ()
+ 以重新啟動應用程式。
當您在瀏覽器開啟 http://0.0.0.0:9292/content/sample.html 時,應該會顯示您範例頁面的內容:
+
+
+ Ktor 提供對
若要使用此功能,請按照以下步驟操作:
+
+ 導覽至
+
開啟
testApplication() 函式會建立一個新的 Ktor 執行個體。此執行個體是在測試環境中執行的,而不是在 Netty 等伺服器上執行。
接著您可以使用 configure() 函式來調用與 embeddedServer() 中相同的設定。
最後,您可以使用內建的 client 物件和 JUnit 判斷提示來發送範例請求並檢查回應。
+ 您可以使用 IntelliJ IDEA 中執行測試的任何標準方式來執行該測試。請注意,由於您正在執行一個新的 Ktor 執行個體,測試的成功與否並不取決於您的應用程式是否正在 0.0.0.0 執行。
+
+ 如果您已成功完成新增 HTTP 端點,請新增此額外測試: +
+新增以下額外匯入:
+
+ 您可以使用
+ 在接下來的步驟中,您將學習如何手動新增和配置此外掛程式。實現這一目標有四個步驟: +
+ +在
+
開啟
按下
+
導覽至 .configureRouting() 方法,並新增以下程式碼行:
這些行安裝了 StatusPages 外掛程式,並指定了當拋出 IllegalStateException 類型的例外時要採取的動作。
新增以下匯入:
++ 請注意,通常會在回應中設定 HTTP 錯誤碼,但出於此任務的目的,輸出會直接顯示在瀏覽器中。 +
+保留在 .configureRouting() 方法中,新增如下所示的額外路由:
您現在已經新增了一個 URL 為 /error-test 的端點。當觸發此端點時,將拋出一個在處理常式中使用的類型的例外。
點擊重新執行按鈕 ()
+ 以重新啟動應用程式。
在您的瀏覽器中,導覽至 URL http://0.0.0.0:9292/error-test。 + 您應該會看到如下所示的錯誤訊息:
+
+ + 如果您已經完成了這些額外任務,那麼您現在已經初步掌握了配置 Ktor 伺服器、整合 Ktor 外掛程式以及實作新路由的方法。然而,這僅僅是個開始。若要更深入地了解 Ktor 的核心概念,請繼續閱讀本指南中的下一個教學。 +
+
+ 接下來,您將學習如何藉由建立一個
+ 程式碼範例: + embedded-server、 + engine-main、 + engine-main-yaml +
+
+ 在建立 Ktor 應用程式之前,您需要考慮應用程式將如何
+
+ 作為一個
+
+ 在這種情況下,用於處理網路請求的應用程式
+ 作為一個
+
+ 在這種情況下,Ktor 應用程式可以部署在 servlet 容器(例如 Tomcat 或 Jetty)中, + 由容器控制應用程式的生命週期和連線設定。 +
+
+ 若要將 Ktor 伺服器應用程式作為獨立的軟件包交付,您需要先建立一個伺服器。
+ 伺服器配置可以包含不同的設定:
+ 伺服器
+ embeddedServer 函式是在
+
+ 程式碼中配置伺服器參數
+
+ 並快速執行應用程式的簡單方法。
+
+ EngineMain 提供更靈活的伺服器配置方式。您可以
+
+ 在檔案中指定伺服器參數
+
+ 並在不重新編譯應用程式的情況下更改配置。此外,您可以從命令列執行應用程式,並透過傳遞對應的命令列引數來覆寫必要的伺服器參數。
+
+ embeddedServer 函式是在
+ Netty 引擎執行伺服器,並監聽 8080 連接埠:
+
+ 有關完整範例,請參閱 + + embedded-server + + 。 +
+
+ EngineMain 使用選定的引擎啟動伺服器,並從外部
+ 除了指定要載入的模組外,配置文件還可以包含各種伺服器參數,例如連接埠、主機和 SSL 設定。例如,下方的配置將伺服器連接埠設定為 8080。
+
EngineMain.main() 立即啟動伺服器,您還可以使用 EngineMain.createServer() 手動建立伺服器執行個體。如需更多資訊,請參閱 。
+ + 有關完整範例,請參閱 + + engine-main + + 和 + + engine-main-yaml + + 。 +
+
+ Ktor 應用程式可以在包含 Tomcat 和 Jetty 的 servlet 容器中執行和部署。
+ 若要部署在 servlet 容器中,您需要產生一個
+
+ 程式碼範例: + + %example_name% + +
+
+ 使用的外掛程式:
+ 在本教學中,我們將解釋如何使用 Kotlin 和 Ktor 建置後端服務,其中包含一個會產生 JSON 檔案的 RESTful API 範例。 +
+
+ 在
+ 您將學習如何執行以下操作: +
+您可以獨立進行本教學,
+ 但我們強烈建議您先完成之前的教學,以學習如何
我們建議您安裝 IntelliJ IDEA,但您也可以使用其他您偏好的 IDE。 +
+在本教學中,您將把現有的工作管理員重寫為 RESTful 服務。為此,您將使用多個 Ktor
+ 雖然您可以手動將其新增到現有專案中,但產生一個新專案,然後逐步加入前一個教學的程式碼會更簡單。您將在過程中重新審視所有程式碼,因此不需要手邊備有前一個專案。 +
++ 前往 + Ktor Project Generator。 +
+在
+
+
+ 在外掛程式區段中,搜尋並點擊
+
+
+ 新增外掛程式後,您將看到專案設定下方列出的所有外掛程式。
+
+
+ 點擊
+
在 IntelliJ IDEA 中開啟您的專案,如之前的 在 IntelliJ IDEA 中開啟、探索並執行您的 Ktor 專案 教學所述。
+
+ 導覽至
+
+ 在
+
+ 開啟
+ enum 來表示優先級,以及一個 class 來表示任務:
+
+ 在前一個教學中,您使用擴充函式將 Task 轉換為 HTML。而在這裡,
+ Task 類別標註了來自
+ kotlinx.serialization 程式庫的 Serializable 型別。
+
+ 開啟
+
+ 與之前的教學類似,您為指向 URL /tasks 的 GET 請求建立了一個路由。
+ 這一次,您不再需要手動轉換任務清單,而是直接回傳該清單。
+
在 IntelliJ IDEA 中,點擊執行按鈕
+ ()
+ 來啟動應用程式。
+ 在瀏覽器中導覽至 http://0.0.0.0:8080/tasks。您應該會看到任務清單的 JSON 版本,如下所示: +
+
+ 顯然,背後已經為我們完成了很多工作。究竟發生了什麼事?
+
+ 當您建立專案時,您包含了
+ 在 HTTP 中,用戶端透過 Accept 標頭發出它可以呈現哪些內容類型的訊號。此標頭的值是一個或多個內容類型。在上述情況下,您可以透過使用瀏覽器內建的開發人員工具來檢查此標頭的值。
+
+ 考慮以下範例: +
+請注意 */* 的包含。此標頭發出它接受 HTML、XML 或圖片的訊號,但也接受任何其他內容類型。
Content Negotiation 外掛程式需要找到一種格式來將資料傳回瀏覽器。如果您查看專案中產生的程式碼,您會在
+
+ 這段程式碼安裝了 ContentNegotiation 外掛程式,同時也配置了 kotlinx.serialization 外掛程式。有了這個,當用戶端發送請求時,伺服器可以回傳序列化為 JSON 的物件。
+
+ 在瀏覽器請求的情況下,ContentNegotiation 外掛程式知道它只能回傳 JSON,而瀏覽器會嘗試顯示發送給它的任何內容。所以請求成功了。
+
+ 在生產環境中,您通常不會直接在瀏覽器中顯示 JSON。相反地,在瀏覽器中執行的 JavaScript 程式碼會發出請求,然後將回傳的資料作為單頁應用程式 (SPA) 的一部分進行顯示。通常,這種應用程式是使用像 React、 + Angular 或 Vue.js 這樣的架構編寫的。 +
+
+ 為了模擬這種情況,請開啟
+
+ 此頁面包含一個 HTML 表單和一個空表格。在提交表單時,JavaScript 事件處理常式會向 /tasks 端點發送請求,並將 Accept 標頭設置為 application/json。回傳的資料隨後被反序列化並新增到 HTML 表格中。
+
+ 在 IntelliJ IDEA 中,點擊重新執行按鈕 () 以重啟應用程式。
+
+ 導覽至 URL http://0.0.0.0:8080/static/index.html。您應該能夠透過點擊
+
+
+ 既然您已經熟悉了內容協商的過程,請繼續將
+
+ 您可以無需任何修改地重複使用任務存儲庫,所以讓我們首先執行此操作。 +
+
+ 在
+
+ 開啟
+
+ 既然您已經建立了存儲庫,就可以實作 GET 請求的路由。之前的程式碼可以簡化,因為您不再需要擔心將任務轉換為 HTML: +
+
+ 導覽至
+
+ 使用以下實作更新 Application.configureRouting() 函式內的 /tasks 路由程式碼:
+
+ 有了這個,您的伺服器可以回應以下 GET 請求:
+/tasks 回傳存儲庫中的所有任務。/tasks/byName/{taskName} 回傳按指定的 taskName 過濾的任務。
+ /tasks/byPriority/{priority} 回傳按指定的 priority 過濾的任務。
+
+ 在 IntelliJ IDEA 中,點擊重新執行按鈕 () 以重啟應用程式。
+
您可以在瀏覽器中測試這些路由。例如,導覽至 http://0.0.0.0:8080/tasks/byPriority/Medium
+ 以 JSON 格式查看所有優先級為 Medium 的任務:
+ + 鑑於這些類型的請求通常來自 JavaScript,更精細的測試更為理想。對此,您可以使用專門的工具,例如 Postman。 +
+在 Postman 中,使用 URL 建立一個新的 GET 請求
+ http://0.0.0.0:8080/tasks/byPriority/Medium。
+ 在
+ application/json。
+
點擊
+
+ 在 IntelliJ IDEA Ultimate 中,您可以在 HTTP 請求檔案中執行相同的步驟。
+
+ 在專案根目錄中,建立一個新的
+
+ 開啟
+
+ 要在 IntelliJ IDEA 中發送請求,請點擊其旁邊的裝訂邊圖示 ()。
+
這將在
+
+
+ 在前一個教學中,任務是透過 HTML 表單建立的。然而,由於您現在正在建置 RESTful 服務,您不再需要那樣做。相反地,您將利用 kotlinx.serialization 架構,它將承擔大部分繁重的工作。
+
+ 開啟
+
+ 向 Application.configureRouting() 函式新增一個新的 POST 路由,如下所示:
+
+ 新增以下新匯入: +
+
+ 當向 /tasks 發送 POST 請求時,會使用 kotlinx.serialization 架構將請求的主體轉換為 Task 物件。如果成功,任務將新增到存儲庫中。如果反序列化過程失敗,伺服器會處理 SerializationException,而如果任務名稱重複,則會處理 IllegalStateException。
+
+ 重啟應用程式。 +
+
+ 要在 Postman 中測試此功能,請向 URL http://0.0.0.0:8080/tasks 建立一個新的 POST 請求。
+
+ 在
+
+ 點擊
+
+ 您可以透過向 http://0.0.0.0:8080/tasks 發送 GET 請求來驗證任務是否已新增。 +
++ 在 IntelliJ IDEA Ultimate 中,您可以透過將以下內容新增到您的 HTTP 請求檔案來執行相同的步驟: +
++ 您即將完成向服務新增基本操作。這些操作通常被總結為 CRUD(建立 Create、讀取 Read、更新 Update 和刪除 Delete)操作。現在您將實作刪除操作。 +
+
+ 在
+ TaskRepository 物件內新增以下方法以根據名稱移除任務:
+
+ 開啟
+ routing() 函式中新增一個端點以處理 DELETE 請求:
+
+ 重啟應用程式。 +
++ 將以下 DELETE 請求新增到您的 HTTP 請求檔案中: +
+
+ 要在 IntelliJ IDEA 中發送 DELETE 請求,請點擊其旁邊的裝訂邊圖示 ()。
+
您將在
+
+
+ 到目前為止,您一直手動測試應用程式,但正如您已經注意到的,這種方法耗時且無法擴充。相反地,您可以實作 client 物件來獲取並反序列化 JSON。
+
+ 開啟
+
+ 將
+
+ 請注意,您需要將 ContentNegotiation 和 kotlinx.serialization 外掛程式安裝到 Plugins 中,就像在伺服器端所做的一樣。
+
+ 將以下相依性新增到您的
+
+ 使用 Ktor client 或類似的程式庫測試服務固然方便,但從品質保證 (QA) 的角度來看,它有一個缺點。伺服器不直接處理 JSON,因此無法確定其對 JSON 結構的假設。 +
++ 例如,諸如以下的假設: +
+object 時,值正被儲存在 array 中。numbers 儲存,而它們實際上是 strings。+ 如果您的服務旨在供多個用戶端使用,那麼對 JSON 結構有信心至關重要。為了實現這一點,請使用 Ktor Client 從伺服器檢索文本,然後使用 JSONPath 程式庫分析此內容。
+在您的
+ dependencies 區塊:
+
+ 導覽至
+
+ 開啟
+
+ JsonPath 查詢的工作原理如下: +
+$[*].name 表示「將文件視為陣列,並回傳每個項目的 name 屬性值」。
+ $[?(@.priority == '$priority')].name 表示「回傳陣列中優先級等於提供值的所有項目的 name 屬性值」。
+ + 您可以使用類似這樣的查詢來確認您對回傳 JSON 的理解。當您進行程式碼重構和服務重新部署時,序列化中的任何修改都會被識別出來,即使它們沒有破壞當前架構的反序列化。這使您能夠充滿信心地重新發布公開可用的 API。 +
++ 恭喜!您現在已經完成了為工作管理員應用程式建立 RESTful API 服務,並學習了使用 Ktor Client 和 JsonPath 進行單元測試的細節。
+
+ 繼續閱讀
+
+ 程式碼範例: + + %example_name% + +
+
+ 使用的外掛程式:
+ 在本教學中,您將學習如何使用 Kotlin、Ktor 與 Thymeleaf 範本建置一個互動式網站。 +
+
+ 在
+ 您可能希望將所有實作保留在伺服器上,僅將標記傳送到用戶端,原因有很多,例如: +
+
+ Ktor 透過整合
+ 您可以獨立完成本教學,但我們強烈建議您先完成
我們建議您安裝 IntelliJ IDEA,但您也可以使用您選擇的其他編輯器。 +
+
+ 在本教學中,您將把在
+ 雖然您可以手動將這些外掛程式新增到現有專案中,但產生一個新專案並逐漸納入先前教學中的程式碼會更容易。我們將在過程中提供所有必要的程式碼,因此您不需要手邊有先前的專案。 +
++ 導航至 + Ktor Project Generator。 +
+
+ 在
+
+
在下一個畫面中,點擊
+
+
+ 新增外掛程式後,您將看到專案設定下方列出了所有三個外掛程式。
+
+
+ 點擊
+
+ 在
+ enum 來表示優先級,以及一個 data class 來表示任務:
+
+ 再次地,您想要建立 Task 物件並以可以顯示的形式傳送給用戶端。
+
+ 您可能還記得: +
+kotlinx.serialization 程式庫中的 Serializable 型別對 Task 類別進行了註解。
+ + 在這種情況下,目標是建立一個伺服器頁面,將任務內容寫入瀏覽器。 +
+
+ 在 .configureRouting() 函式中,為 /tasks 新增一條路由,如下所示:
+
+ 當伺服器收到對 /tasks 的請求時,它會建立一個任務清單,然後將其傳遞給 Thymeleaf 範本。ThymeleafContent 型別接收要觸發的範本名稱,以及要在頁面上存取的值表。
+
您應該會看到以下 .configureThymeleaf 函式:
+ 在 Thymeleaf 外掛程式的初始化過程中,Ktor 會在
+
+ 在這種情況下,名稱 all-tasks 對應到路徑
+ src/main/resources/templates/thymeleaf/all-tasks.html
+
開啟
+
在 IntelliJ IDEA 中,點擊執行按鈕
+ ()
+ 來啟動應用程式。
+ 在瀏覽器中導航至 http://0.0.0.0:8080/tasks。您應該會看到所有目前任務顯示在表格中,如下所示: +
+
+ + 與所有伺服器頁面架構一樣,Thymeleaf 範本混合了靜態內容(要傳送到瀏覽器)與動態內容(要在伺服器上執行)。如果您選擇了其他架構,例如 Freemarker,您也可以使用稍微不同的語法提供相同的功能。 +
+現在您已經熟悉了請求伺服器頁面的過程,請繼續將先前教學中的功能轉移到本教學中。
+因為您包含了
+
+ 這意味著,例如,對 /static/index.html 的請求會由以下路徑的內容提供:
+
src/main/resources/static/index.html
+ + 由於此檔案已經是產生的專案的一部分,您可以將其用作您希望新增的功能的首頁。 +
+
+ 開啟
+
+ 在 IntelliJ IDEA 中,點擊重新執行按鈕 () 以重新啟動應用程式。
+
+ 在瀏覽器中導航至 http://localhost:8080/static/index.html。您應該會看到一個連結按鈕和三個 HTML 表單,允許您查看、篩選與建立任務: +
+
+
+ 請注意,當您按 name 或 priority 篩選任務時,您是透過 GET 請求提交 HTML 表單。這意味著參數會新增到 URL 後方的查詢字串中。
+
+ 例如,如果您搜尋 Medium 優先級的任務,傳送到伺服器的請求如下所示:
+
http://localhost:8080/tasks/byPriority?priority=Medium
+ + 任務的存儲庫可以保持與先前教學中的內容完全相同。 +
+
+ 在
+
+ 現在您已經建立了存儲庫,可以實作 GET 請求的路由。 +
+
+ 將目前版本的 .configureRouting() 替換為以下實作:
+
+ 上述程式碼可以總結如下: +
+/tasks 的 GET 請求中,伺服器從存儲庫中檢索所有任務,並使用
+ /tasks/byName 的 GET 請求中,伺服器從 queryString 中檢索參數 name,找到相符的任務,並使用
+ /tasks/byPriority 的 GET 請求中,伺服器從 queryString 中檢索參數 priority,找到相符的任務,並使用
+ 為了使這一切正常運作,您需要新增額外的範本。
+
+ 開啟
+
在同一個資料夾中,建立一個名為
+
+ 開啟
+
+ 接下來,您將在 /tasks 中新增一個 POST 請求處理常式,以執行以下操作:
+
+ 在 .configureRouting() 方法中新增以下 post 請求路由:
+
+ 在 IntelliJ IDEA 中,點擊重新執行按鈕 () 以重新啟動應用程式。
+
+ 在
+
+ 點擊
+
+ + 恭喜!您現在已完成將 Task Manager 重建為 Web 應用程式,並學習了如何使用 Thymeleaf 範本。
+
+ 繼續閱讀
+ 程式碼範例: + + %example_name% + +
+
+ 使用的外掛程式:
+ 本文將引導你完成使用 Ktor 在 Kotlin 中建立 WebSocket 應用程式的過程。它建立在
本文將教你如何執行以下操作:
+你可以獨立完成此教學,但我們建議你先完成
+
我們建議你安裝 IntelliJ + IDEA,但你也可以使用其他偏好的 IDE。 +
+
+ 在本教學中,你將基於 Task 物件的功能。為了實現這一點,你需要加入
+ 導覽至 + Ktor 專案產生器。 +
+在
+
+
+ 在外掛程式區段搜尋並點擊
+
+
+
+ 加入外掛程式後,它們將顯示在外掛程式區段的右上角。 +
+你將看到所有即將加入專案的外掛程式清單:
+
+
+ 點擊
+
下載完成後,在 IntelliJ IDEA 中開啟專案並遵循以下步驟:
+
+ 在
+
+ 開啟
+ enum 來表示優先級,以及一個 data class 來表示任務:
+
+ 請注意,Task 類別標記了來自 kotlinx.serialization 程式庫的 Serializable 註解。這意味著執行個體可以與 JSON 互相轉換,從而允許其內容在網路上傳輸。
+
+ 因為你包含了 WebSockets 外掛程式,產生器已在
+ webSocket 路由,並在
+
.configureWebsockets() 函式替換為以下內容:
+ contentConverter 屬性,使外掛程式能夠透過 kotlinx.serialization 程式庫序列化傳送與接收的物件。
+
+ 開啟
+ Application.configureRouting() 函式替換為下方的實作:
+
/tasks。
+
+ 為了示範目的,在傳送任務之間引入了一秒鐘的延遲。這讓你可以觀察到任務在用戶端中逐一出現。若沒有這個延遲,此範例看起來會與先前文章中開發的
+ 此階段的最後一步是為此端點建立一個用戶端。因為你包含了
+
+ 開啟
+
+ 此頁面使用了所有現代瀏覽器都提供的 WebSocket 類型。你在 JavaScript 中建立此物件,並將端點的 URL 傳遞給建構函式。隨後,你為 onopen、onclose 和 onmessage 事件附加事件處理常式。觸發 onmessage 事件時,你會使用文件物件的方法向表格附加一行。
+
在 IntelliJ IDEA 中,點擊執行按鈕
+ ()
+ 來啟動應用程式。
+ 導覽至 http://0.0.0.0:8080/static/index.html。你應該會看到一個包含按鈕的表單和一個空表格: +
+
+
+ 點擊表單後,任務會從伺服器載入,並以每秒一個的速度出現。因此,表格會逐次填入內容。你也可以透過開啟瀏覽器
+ + 至此,該服務運作符合預期。WebSocket 連線已開啟,項目被傳送至用戶端,隨後連線關閉。底層網路存在許多複雜性,但 Ktor 預設處理了所有這些細節。 +
++ 在進入下一個階段之前,回顧 WebSockets 的一些基本概念可能會有所幫助。如果你已經熟悉 WebSockets,可以直接繼續 改進你的服務設計。 +
++ 在先前的教學中,你的用戶端傳送 HTTP 請求並接收 HTTP 回應。這種模式運作良好,並使網際網路具備擴展性與韌性。 +
+然而,它不適用於以下情境:
++ 這些情境的範例包括股票交易、購買電影和音樂會門票、線上拍賣競標,以及社群媒體中的聊天功能。WebSockets 的開發就是為了處理這些情況。 +
+
+ WebSocket 連線建立在 TCP 之上,且可以持續較長時間。該連線提供
+ WebSocket API 定義了四種事件(open、message、close 和 error)以及兩種操作(send 和 close)。如何存取這些功能可能因不同的語言和程式庫而異。例如,在 Kotlin 中,你可以將傳入訊息序列視為 Flow 來處理。
+
接下來,你將重構現有程式碼,為更進階的範例騰出空間。
+
+ 在
+
+ 開啟
+ TaskRepository 類型:
+
你可能還記得先前教學中的這段程式碼。
+
+ 你現在可以透過利用 TaskRepository 來簡化 Application.configureRouting() 中的路由:
+
+ 為了說明 WebSockets 的強大功能,你將建立一個新的端點,其中: +
+
+ 在
+ .configureRouting() 方法替換為下方的實作:
+
透過這段程式碼,你完成了以下操作:
+routing {} 區塊中,建立了一個執行緒安全的 session 物件清單,用以追蹤所有用戶端。
+ /tasks2 的新端點。當用戶端連接到此端點時,對應的 session 物件會被加入清單。伺服器隨後進入無限迴圈,等待接收新任務。收到新任務後,伺服器將其存儲在存儲庫中,並向所有用戶端(包括當前用戶端)發送複本。
+
+ 為了測試此功能,你將建立一個新頁面,擴充
+
+ 在
+
+ 開啟
+
+ 這個新頁面引入了一個 HTML 表單,使用者可以在其中輸入新任務的資訊。提交表單後,會呼叫 sendTaskToServer() 事件處理常式。這會使用表單資料建立一個 JavaScript 物件,並使用 WebSocket 物件的 .send() 方法將其傳送至伺服器。
+
+ 在 IntelliJ IDEA 中,點擊重新執行按鈕 () 來重新啟動應用程式。
+
要測試此功能,請並排開啟兩個瀏覽器並遵循以下步驟。
+
+
+ 為了簡化你的品質保證 (QA) 流程並使其快速、可重現且自動化,你可以使用 Ktor 內建的
+ 將以下相依性加入
+
+
在 IntelliJ IDEA 中,點擊編輯器右側的 Gradle 通知圖示
+ ()
+ 來載入 Gradle 變更。
+ 導覽至
+
+ 將產生的測試類別替換為下方的實作: +
++ 透過此設定,你: +
+Tasks 清單。
+ client 物件的 .webSocket 函式向 /tasks 傳送請求。
+ Flow 處理,並將其逐一加入清單。
+ expectedTasks 與 actualTasks。
+ + 做得好!透過結合 WebSocket 通訊與 Ktor Client 的自動化測試,你已顯著增強了工作管理器服務。 +
+
+ 繼續閱讀
+
+ 在本主題中,我們將向您展示如何將 Ktor Server 所需的相依性新增至現有的 + Gradle/Maven 專案。 +
++ 在新增 Ktor 相依性之前,您需要為此專案設定存儲庫: +
+
+
+ Ktor 的生產版本可在 Maven 中央存儲庫中取得。 + 您可以在建置指令碼中宣告此存儲庫,如下所示: +
+
+ 您不需要在
+
+ 要存取 Ktor 的 EAP 版本,您需要參照 Space 存儲庫: +
++ 請注意,Ktor EAP 可能需要 Kotlin 開發存儲庫: +
++ 每個 Ktor 應用程式至少需要以下相依性: +
+
+ ktor-server-core:包含核心 Ktor 功能。
+
+ 一個ktor-server-netty)。
+
+ 對於不同的平台,Ktor 提供特定平台的成品 (artifacts),並帶有 -jvm 等後綴,例如 ktor-server-core-jvm 或 ktor-server-netty-jvm。
+ 請注意,Gradle 會解析適合特定平台的成品,而 Maven 不支援此功能。
+ 這意味著對於 Maven,您需要手動新增特定平台的後綴。
+ 一個基礎 Ktor 應用程式的 dependencies 區塊可能如下所示:
+
+ Ktor 使用 SLF4J API 作為各種記錄架構(例如 Logback 或 Log4j)的介面,並允許您記錄應用程式事件。 + 要了解如何新增所需的成品,請參閱新增記錄器相依性。 +
+
+ 擴充 Ktor 功能的
+ 套用 Ktor Gradle 外掛程式 + 會隱含地新增 Ktor BOM 相依性,並允許您確保所有 Ktor 相依性都處於 + 相同版本。在這種情況下,當相依於 Ktor + 成品時,您不再需要指定版本: +
++ 您也可以透過使用發佈的版本目錄 (version catalog) 來集中 Ktor 相依性宣告。 + 此方法具有以下優點: +
+
+ 要宣告目錄,請在
+
+ 然後,您可以透過參照目錄名稱,在模組的
+
+ 使用 Gradle/Maven
+ 如果您使用 embeddedServer,請按如下方式指定主類別: +
++ 如果您使用 EngineMain,您需要將其配置為主類別。 + 對於 Netty,它將如下所示: +
++ 如果您打算將應用程式封裝為 Fat JAR,則在配置相應的外掛程式時,還需要考慮建立伺服器的方式。 + 請從以下主題中了解更多資訊: +
+
+
+
+ Ktor 提供了一種專門針對開發的特殊模式。此模式啟用了以下功能: +
++ 請注意,開發模式會影響效能,不應在生產環境中使用。 +
++ 您可以透過不同的方式啟用開發模式:在應用程式配置檔案中、使用專用的系統屬性或環境變數。 +
+
+ 若要在 development 選項設為 true:
+
+
+ 若要使用 IntelliJ IDEA 在開發模式下執行應用程式,請將 io.ktor.development 搭配 -D 旗標傳遞給 虛擬機選項:
+
+ 如果您使用
+ 在您的 ktor 區塊:
+
+ 透過傳遞 Gradle CLI 旗標來為單次執行啟用開發模式: +
+
+ 您也可以使用 -ea 旗標來啟用開發模式。請注意,使用 -D 旗標傳遞的 io.ktor.development 系統屬性優先級高於 -ea。
+
+ 若要為 原生用戶端啟用開發模式,請使用 io.ktor.development 環境變數。
+