今回の内容
前々回、HerokuでExpressアプリを作る---基本設定、前回、ExpressとPostgresqlを使ってHerokuでログインページを作る、の続き。
今回はExpressをWebSocketサーバーとしてチャットを作る。ExpressでのWebSocket関連は色々な解説があるがexpress-ws
を使うのが便利だった1。
クライアント側には素のWebSocketのみを使った。
サーバー側の実装
$ yarn add express-ws
でexoress-wsをインストールする。express-wsはappをセットするだけでapp.ws(path, callback)
の形で使えるようになる
前々回までの基本部分、以外の追加分は
const expressWs=require('express-ws')(app);
const chat=require('./src/chat');
//*** 略 ***//
app.ws('/chat', chat);
実装はsrc/chat.js
と別ファイルにしておくデータのやり取りはJSON形式を使う。clientにはnameプロパティがなかったのでここに接続ユーザー名を付けておく
let clients=[];
const chat=(ws, req)=>{
clients.push(ws);
ws.on('message', message=>{
const json=JSON.parse(message);
clients.forEach(a=>{ if( a===ws && a.name==null ) a.name=json.user });
if( json.method!=null ) json.clients=clients.map(a=> a.name);
clients.forEach(a=>{ a.send(JSON.stringify(json)); });
});
ws.on('close', ()=>{
const name=clients.find(a=> a===ws).name;
clients=clients.filter(a=> a!==ws);
clients.forEach(a=>{ a.send(JSON.stringify({ user: name, method: 'close', clients: clients.map(a=>name) })); });
});
}
module.exports=chat;
クライアント側実装
window.addEventListener('DOMContentLoaded', ()=>{
const name=prompt('名前を入れてください');
document.getElementById('name').value=name;
const ws=new WebSocket(location.origin.replace('https', 'wss')+'/chat');
ws.addEventListener('open', ()=>{ ws.send(JSON.stringify({ user: name, method: 'connect' })); });
const input=document.getElementById('input');
document.getElementById('send').addEventListener('click', ()=>{
const text=input.value;
if( text.length>0 ){
const json={ user: name, message: text };
ws.send(JSON.stringify(json));
}
input.value='';
});
const output=document.getElementById('output');
ws.addEventListener('message', message=>{
const json=JSON.parse(message.data);
const line=document.createElement('div');
if( json.clients!=null ){
document.getElementById('n-client').innerHTML='只今、'+json.clients.length+'人が接続しています';
if( json.method==='connect' ){ line.innerHTML=json.user+'が接続しました'; }
else if( json.method==='close' ){ line.innerHTML=json.user+'が接続を切りました'; }
else console.log(不正なメソッドです, json.method);
output.appendChild(line);
}
else if( json.message!=null ){
line.innerHTML=json.user+' > '+json.message;
output.appendChild(line);
}
else{ console.log('不正なデータ形式です'); }
});
});
新たな接続があればopen
イベントでサーバーに送っています。close
はサーバー側で自動的に感知してくれるので書く必要はありません。
サーバーが送ったデータはmassage.data
に入っています。データによって出力側に色々書き出しています。
完成品
デザインはかなり適当ですが...、こんな感じでチャットができます。
あとがき
難しそうでしたがexpress-wsさえ使えば簡単にWebSocketが使えました、サーバーとクライアント側のデータの不一致でJavaScriptが死んだりはかなりしましたが...。
express-wsだとルーターの設定も簡単にできたので便利でした。
closeイベントも自動的に感知してくれたのでセッション管理などにも使えそうな気がしました。