サイトロゴ

Enjoy Creating
Web & Mobile Apps

MENU BOX
WEB
MOBILE
OPEN

ホーム

 > 

 > 

KtorでWebサイト制作【コメント投稿機能実装編】

KtorでWebサイト制作【コメント投稿機能実装編】

この記事にはプロモーションが含まれています。

前回の記事では静的リソースを利用する方法について説明しました。これにより、静的なWebサイトならすでにKtorで作り上げることができる状態になりました。

ですが、せっかくKtorを利用するのであればバックエンドの処理を利用して、動的な機能を実装してみたいですよね。

ということで今回は仕上げとして、『シンプルなコメント投稿機能』を追加していきます。

注意1:この記事はシリーズ形式となっています。プロジェクトのディレクトリ・コードなどの状況は前回のものを引き継いでいます。

注意2:この記事では解説をよりシンプルに保つため、データベースは扱いません。また、セキュリティについても最低限の対策しか行っていません。

この記事を読むことで分かること
  • ・Ktorで動的なデータを取り扱う方法
  • ・FreeMarkerの機能を利用してセキュリティ対策を行う方法

– 目次 –

STEP1: フォームタグを配置する

コメント投稿機能を実装するにあたり、コメントをサーバに送信するために必要なタグを index.ftl ファイル内に配置する必要があります。最低限、次の要素が必要です。

  • テキスト(コメント)を入力するための入力エリア
  • コメントをサーバに送信するための送信ボタン
  • 上記の要素が一つのまとまったフォームであることを示すためのフォームタグ

なおHTTPリクエストには様々な種類がありますが、フォームに入力された内容をサーバに送信する際はPOSTメソッドが使用されます。HTTPリクエストについてもう少し詳しく知りたい場合は、MDNのサイトを参考にするのがオススメです。(シンプルに情報がまとまっています)

・HTTP リクエストメソッド – HTTP | MDN
https://developer.mozilla.org/ja/docs/Web/HTTP/Methods

index.ftl に配置するフォーム関連のマークアップ例は次のようになります。

index.ftl

<form action="/" method="post">
    <input type="text" name="comment">
    <button>Submit</button>
</form>

button要素のtype属性のデフォルト値は submit であり、これはサーバにフォームデータを送信するための値です。そしてこのボタンはサーバにデータを送信する目的で配置しているので、特に明示的にtype属性を指定する必要はありません。(もちろん、type="submit"としても問題はありません)

これでフォームタグの配置は完了です。(コメントをページに反映するためのコードは後で追加します)

次のステップで、バックエンド側の処理を記述していきましょう!

STEP2: フォームデータを加工して処理する

このステップではPOSTメソッドで送られたデータをサーバで処理・加工し、それをテンプレートエンジン(index.ftl)に返すところまで行います。

まず、コメント(文字列)を格納するための変数を宣言しておく必要がありますね。本番環境では、動的なデータを定義したり加工処理したりするコードを記述する用のディレクトリやファイルを作成し、その他の機能・ファイルとは分けて管理することが多いのですが、ここでは構造をシンプルに保つため全て Rooting.kt ファイル内に記述していくことにします。

次のように、送信されたコメントを管理するための MutableList<String> を宣言します。なお、初期値として "The first comment" という値を一つ指定しています。

Routing.kt

val comments = mutableListOf(
    "The first comment",
)

そして次に、POSTメソッドに対するサーバサイドの処理を記述します。まず、送信されたフォームパラメータ(コメント)を受け取る必要がありますね。次のように記述することで、値を取得することができます。

Routing.kt

post("/") {
    val formParams = call.receiveParameters()
    val comment = formParams["comment"] ?: ""
}

値を取得したら MutableList にそれを追加し、ページに反映させるために元のページにリダイレクトする必要があります。それらのコードを追加すると、次のようになります。

Routing.kt

post("/") {
    val formParams = call.receiveParameters()
    val comment = formParams["comment"] ?: ""
    comments.add(comment)
    call.respondRedirect("/")
}

ただ、現時点では index.ftl にリダイレクトしたところでコメントは反映されません。GETメソッドでコメントを渡す処理を追加してないですし、index.ftl 内でもコメントを反映するためのタグを追加していないからです。

次のステップではそれらを追加していきましょう。

STEP3: コメントをページに反映させる

前のステップに引き続き、Routing.kt ファイルを編集していきましょう。現在、GETメソッドでは単に index.ftl が読み込まれるように設定されているだけであり、FreeMarkerContentの第二パラメータである model には null が指定されています。

Routing.kt

get("/") {
    call.respond(FreeMarkerContent(
        "index.ftl",
        null
    ))
}

この model パラメータに値(コメントリスト)を指定することができます。コード例は次のようになります。

Routing.kt

get("/") {
    call.respond(FreeMarkerContent(
        "index.ftl",
        mapOf("comments" to comments)
    ))
}

次に、index.ftl テンプレートファイルを修正していきます。FreeMarkerには動的なデータを取り扱うための様々な機能があります。その一つが <#list> ~ </#list> を使ったデータリストの展開です。

コメント送信フォームの下に、次のようにコメントを表示するためのリストタグを記述します。

index.ftl

<ul>
    <#list comments as comment>
        <li>${comment}</li>
    </#list>
</ul>

ここではMapのキーとして指定された comments の値を comment として展開し、li要素でマークアップすることでコメントがリスト形式で表示されるようにしています。

こういったデータの展開や条件分岐等、動的にデータを取り扱う上で欠かせないFreeMakerの基本的な機能は公式サイトで確認することができます。

・list, else, items, sep, break, continue – Apache FreeMarker Manual
https://freemarker.apache.org/docs/ref_directive_list.html

これで一応、シンプルなコメント投稿機能の完成です。実際にコメントを投稿してみると、送信したコメントがちゃんと画面に反映されることが確認できます。※スタイル(CSS)調整は別途加えています

コメント送信がページに反映されていることを示すスクリーンショット画像

データベースを導入していないので、プロジェクトを立ち上げるたびにデータ(送信されたコメント)は失われてしまいますが、記事の冒頭で述べたように、データベースを導入するとコードが複雑になりすぎてしまうためこのシリーズでは割愛させていただきます。

また、現時点ではコメント投稿機能に致命的なセキュリティ上の問題があります。最後にその問題を解決していきましょう。

STEP4: セキュリティの問題を解決する

現在、コメント入力欄では無制限に文字入力を受けつけており、さらに入力された文字を加工することなく画面に反映させている状態です。このままでは、クロスサイトスクリプティング攻撃(XSS)をモロに受けてしまいます。

下の画像のようにコメント入力欄にアラートを表示するJavaScriptコードを入力して送信してみると、JavaScriptコードが実行されてしまいます。

コメント送信を利用してJavaScriptが実行されていることを示すスクリーンショット画像

これを防止する方法は色々ありますが、FreeMarkerには自動的にサニタイズしてくれる機能が備わっているので、今回はそれを利用することにしましょう。

Templating.kt ファイルを開き、Application.configureTemplating()install(FreeMarker) ブロック内に次のコードを追加します。

Templating.kt

outputFormat = HTMLOutputFormat.INSTANCE

この設定により、< や > などタグとして認識されてしまう特殊な記号がエスケープ処理されます。この状態で先ほどと同様にコメント入力欄にscriptタグを挿入すると、JavaScriptプログラムとして実行はされず、単なる文字列としてコメントに残るだけで無害化されます。

サニタイズされていることを示すスクリーンショット画像

これだけで全ての攻撃を防げるというわけではありませんが、サニタイズするだけでもセキュリティを高められるということがお分かり頂けたかと思います。

おわりに

以上で『KtorでWebサイト制作シリーズ』の完結となります。ここまでお付き合いいただき、本当にありがとうございました!

さらにKtorを使ってバックエンドのスキルを高めたいという方は、ぜひデータベースを導入して動的なデータをサーバのデータベースで管理する方法を学んでみることをオススメします。

また認証機能を追加して、限られたユーザーにのみコメントの投稿を許可するような仕組みを導入するのも良い勉強になるかと思います。

最終的に出来上がったサンプルのコードの全体は GitHub で公開していますので、そちらも合わせて参考資料としてお使いいただければ幸いです。

・GitHub Ktorサンプルプロジェクト
https://github.com/roydo/Ktro-Website-Sample


« »

カテゴリーリンク

著者について- author profile -

ROYDOプロフィール写真
Michihiro

モバイルアプリ(iOS・Android)ディベロッパー&デザイナー

これまでに、可読性の高いカラーパターンを自動で生成するアプリや、『第3火曜日』といった形式で通知をスケジュールできるアプリなどを制作。

サブでWebデザイン・フロントエンドエンジニアとしても活動しています。

📝ツール・言語:JavaScript/React Native/Kotlin/Android Studio/Swift/SwiftUI

🎓資格:応用情報技術者/基本情報技術者/ウェブデザイン技能検定3級

Twitterアイコン Instagramアイコン