こんにちは。KOUKIです。
Go言語とJavaScriptでチャットアプリの作成方法について、記事にしています。
前回は、チャットにアクセスしたユーザーのリストを画面に表示する処理を実装しました。
そろそろWebSocketsにも慣れてきたのではないでしょうか。
前回と同じ要領で、メッセージを表示する機能を実装したいと思います。
<目次>
前回
メッセージ表示機能の実装
チャットからメッセージを送信後、サーバー側で全ユーザーにメッセージをブロードキャストし、チャット上にそれを表示させます。

メッセージを送信する
最初に、チャットからメッセージを送信する機能を実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
// scripts.js document.addEventListener("DOMContentLoaded", function(){ // WebScoektオブジェクトの作成 // 接続を確立 // 接続がCLOSEDに変わった時に呼ばれる // エラーが発生した時に呼び出される // サーバーからメッセージが届いたときに呼び出される ... document.getElementById("message").addEventListener("keydown", function(event) { if (event.code === "Enter") { if (!socket) { console.log("no connection") return false } // HTML要素既存の動きやイベント伝搬をキャンセル event.preventDefault() event.stopPropagation() sendMessage() } }) }) function sendMessage() { console.log("Send Message...") let jsonData = {} jsonData["action"] = "broadcast" jsonData["username"] = document.getElementById("username").value jsonData["message"] = document.getElementById("message").value socket.send(JSON.stringify(jsonData)) document.getElementById("message").value = "" } |
これで、メッセージボックスにメッセージを入力し、Enterを押下するとメッセージが送信されるようになりました。
送信ボタンを押下した時もメッセージを送れるようにbuttonタグを編集します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!-- home.jet --> <!DOCTYPE html> <html lang="en"> <head> ... </head> <body> ... <button id="submit" class="submit" onclick="sendMessage()"> <!-- onclickを追加 --> <i class="far fa-paper-plane"></i> </button> ... </body> </html> |
また、jsonDataに設定しているパラメータ(usernameなど)は、サーバー側のconnect.goに定義したペイロード構造体に合わせています。
1 2 3 4 5 6 7 8 9 10 11 12 |
// connect.go package domain ... // WebSockets送信データを格納 type WsPayload struct { Action string `json:"action"` Message string `json:"message"` Username string `json:"username"` Conn WebScoketConnection `json:"-"` } |
メッセージをbroadcastする
handlers.goのListenToWsChannel関数にboradcastのハンドリング処理を実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// handlers.go func ListenToWsChannel() { var response domain.WsJsonResponse for { // メッセージが入るまで、ここでブロック e := <-wsChan switch e.Action { case "username": ... case "left": ... case "broadcast": response.Action = "broadcast" response.Message = fmt.Sprintf( "<li class='replace'><strong>%s</strong>: %s</li>", e.Username, e.Message) broadcastToAll(response) } } } |
メッセージを表示する
メッセージをチャット上に表示する処理を実装します。
まずは、チャットエリアの情報を取得しましょう。
1 2 3 4 5 6 |
// scripts.js // WebSocketsオブジェクトの作成 // メッセージリストを宣言 let messageList = document.getElementById("message-list") |
次に、WebSocketsのonmessageにbroadcastのハンドリングを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
socket.onmessage = msg => { let data = JSON.parse(msg.data) console.log({data}) console.log("Action is", data.action) switch (data.action) { case "list_users": ... case "broadcast": let message = data.message let username = document.getElementById("username").value // メッセージが自分のものかチェック // classをmeかotherに書き換え if (message.indexOf(username) > 0) { message = message.replace("replace", "me") } else { message = message.replace("replace", "other") } messageList.innerHTML = messageList.innerHTML + message break } } |
動作確認
動作確認をしてみましょう。
下記のコマンドで、サーバーを起動してください。
1 2 3 |
$ go run cmd/web/*.go 2021/04/06 07:30:55 Starting channel listener 2021/04/06 07:30:55 Starting web server on port 8080 |
次にブラウザを2つ開いて、それぞれ「http://localhost:8080」へアクセスし、ユーザー名を入力してからメッセージを送信してみましょう。

いい感じですね。
サーバーリコネクト機能
メッセージ送信・表示機能の実装が完了したので、本記事の目的は達成したのですが、おまけで追加の機能を実装しておきましょう。
サーバーを再起動などすると全てのユーザーのコネクションは、当然ながら切れてしまいます。そして、それは何かと不便なため、サーバーへリコネクトする機能を実装しましょう。
「joewalnes/reconnecting-websocket」を使用すると簡単に実装できます。
ソースコードをダウンロードすると「reconnecting-websocket.min.js」ファイルが格納されているので、それをstaticフォルダに格納してください。
それから、格納したファイルをhome.jetファイルから読み込みます。
1 2 3 4 5 6 7 |
<!-- home.jet --> ... <body> ... <script src="/static/reconnecting-websocket.min.js"></script> <script src="/static/scripts.js"></script> </body> |
必ず、scripts.jsより前に読み込んでください。
GitHubのREADME.mdを読むとWebSocketsオブジェクトの生成方法を次のように変更すれば、使えるようです。
1 2 3 4 5 |
# JavaScriptオリジナルのWebSockets var ws = new WebSocket('ws://....'); # サーバーリコネクション用のWebSockets var ws = new ReconnectingWebSocket('ws://....'); |
scritps.jsを修正します。
1 2 3 4 5 6 7 8 9 |
// scripts.js // WebScoektオブジェクトの作成 socket = new ReconnectingWebSocket( "ws://127.0.0.1:8080/ws", null, { debug: true, reconnectInterval: 3000 // 3s後に再接続 }) |
これだけで再接続してくれるようになるので、めちゃくちゃ便利ですよね。
一度、サーバーをCtrl + cでストップし、「go run cmd/web/*.go」コマンドで立ち上げなおすと、動作を確認することができます。
1 2 3 4 5 6 7 8 9 10 |
$ go run cmd/web/*.go 2021/04/07 07:06:58 Starting channel listener 2021/04/07 07:06:58 Starting web server on port 8080 2021/04/07 07:07:02 OK Client Connecting ^Csignal: interrupt <<< サーバーを止める $ go run cmd/web/*.go <<< サーバーを立ち上げなおす 2021/04/07 07:09:34 Starting channel listener 2021/04/07 07:09:34 Starting web server on port 8080 2021/04/07 07:09:34 OK Client Connecting |

「connection closed」->「Successfully connected」になっているので、リコネクト成功です。
おわりに
WebSocketsは、本当に便利ですね。
今回のような非同期通信で、チャットアプリケーションの実装も簡単にできますし、Push通知機能なんてのもできるかもしれません。
アプリケーション開発の幅がかなり広がると思います^^
それでは、また!
コメントを残す
コメントを投稿するにはログインしてください。