socket.ioはWeb applicationにおいて、双方向通信を可能にする便利なツールです。
色々なサイトでも紹介されいますが、
チャットアプリを例に、ここでは、apache2のリバースプロキシに対応した例を紹介します。
{
"name": "chat",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"server": "node server.js"
},
"author": "",
"license": "",
"dependencies": {
"express": "^4.18.1",
"socket.io": "^4.5.1"
}
}
const app = express();
const PORT = 3000;
const http = require('http').Server(app);
http.listen(PORT, ()=>{ console.log('server listening. Port:' + PORT); });
let messages=[];
app.use(
(req,res,next)=>{
console.log({
url:req.url,
headers:req.headers
});
next();
}
);
//
// client code
//
app.get('/index.html',
(req,res)=>{ res.sendFile(__dirname+`/html/client.html` )}
);
//
// soket communication
//
const io = require('socket.io')(http,{
path:"/socket/" // change path name to socket io
});
io.on('connection',socket=>{
const room=process.argv[2] ? process.argv[2] : "Roomhogehoge"; //auth
const remoteIP=socket.request.headers["x-remote-addr"]? socket.request.headers["x-remote-addr"].split(",")[0]: "undef";
const from=`${decodeURI(socket.request.headers.from)}[${remoteIP}]`;
if(decodeURI(socket.request.headers.room)===room){
//room entry
(()=>{
const msg={
from,
at :(new Date()).toString(),
message:`${from} enters the room.`
};
messages.map( msg=>{
socket.emit("message",msg);
});
messages.push(msg);
io.emit("message",msg);
})();
//room exit
socket.on("disconnect",()=>{
const msg={
from,
at :(new Date()).toString(),
message : `${from} exits from the room.`
};
messages.push(msg);
io.emit("message",msg);
})
// message receive
socket.on("message", msg=>{
try{
const _msg={
from,
at:(new Date()).toString(),
message:msg.message
};
messages.push(_msg);
io.emit("message",_msg)
}catch(e){
console.log(e);
}
})
}else{ // auth fail
socket.emit("message",{
from,
at :(new Date()).toString(),
message : "Please specify the room id you want to enter like https://...../index.html?room=hoge&name=yourname"
});
socket.disconnect();
}
});
<html>
<head>
<meta charset=utf-8>
<style>
pre{
margin:0px;
font-size:10pt;
}
h3{
margin:3px;
}
</style>
</head>
<html>
<body style="font-size:20pt">
<h3>soket.ioを使ったチャットサンプル</h3>
<div style="font-size:0.6em">(apache2の多段リバースプロキシ経由でnode.jsに接続)</div>
<hr>
<div style="width:90%; margin:auto">
<textarea id="inputText" type="text" style="width:90%;height:100px; margin-bottom:5px; overflow:auto"></textarea>
<button id="sendButton">送信 </button>
</div>
<div id="messageList" style="width:90%; margin:auto;" />
<script src="https://cdn.socket.io/4.1.2/socket.io.min.js"
integrity="sha384-toS6mmwu70G0fw54EGlWWeA4z3dyJ+dlXBtSURSKN4vyRFOcxd3Bzjj/AoOwY+Rg"
crossorigin="anonymous">
</script>
<script>
function getParam(key){
try{
return window.location.search
.replace("?","")
.split("&")
.reduce( (prev,param) =>{
const [key,value]=param.split("=")
prev[key]=value; // URI encoded value
return prev;
},{})[key];
}catch(e){
console.log(e);
return null
}
}
getParam();
const room=getParam("room");
const from=getParam("name");
</script>
<script>
const path=window.location.href
.replace(window.location.origin,"")
.replace(/.index.html.*$/,"/socket/"); //socket path
const socket = io(
{
forceNew : true,
path ,
extraHeaders:{ room, from }
});
const addMessageList = (message) => {
const div = document.createElement('div');
try{
const msgJson=JSON.parse(message);
div.innerHTML=`<div style="font-size:0.5em;color:green">${msgJson.from}@${msgJson.at}</div>`+
`<div style="border:1px solid black;background-color:silver;padding:3px; width:100%; overflow:auto; padding:3px">`+
` <pre>${msgJson.message}</pre>`+
`</div>`;
}catch(err){
div.append(message);
}
document.getElementById('messageList').prepend(div);
};
const sendMessage=(message)=>{
socket.emit('message', {from, message});
};
document.getElementById('sendButton').addEventListener('click', () => {
sendMessage(document.getElementById('inputText').value);
document.getElementById('inputText').value = '';
});
socket.on("message",msg=>{
addMessageList(typeof msg=="object" ? JSON.stringify(msg,null," "):msg);
})
</script>
</body>
</html>
RewriteEngine On
RewriteRule .* - [env=remoteaddr:%{REMOTE_ADDR}]
RequestHeader add X-Remote-Addr %{remoteaddr}e
RewriteRule ^(.*)$ http://localhost:3000/$1 [P,L]
追加情報