技術が陳腐化するのは、まるで正月に食べようと思っていたお餅を、正月すぎてみたら、カビが生えてた様なもんだな、と考えた、ユゲタです。
なんだか技術って陳腐化しちゃうので、賞味期限に気をつけなければいけないのは、食べ物だけじゃないという話です。
今回の焦点は、NodejsのPolingの革命児である「Socket.IO」ライブラリです。
通常、仕事などでこういう複雑なライブラリを使う時は、自分用のテンプレートコードを用意しているんですが、
それが、Nodejsを最新版にして、最新バージョンのSocket.IOをinstallしてみたところ、エラーが出て起動すらしない状態でした。
きっと、過去に仕事で作ったサービスのモジュールをアップデートしたら、エラーが出てしまう事でしょう。
幸い、今現在、ユゲタ管轄のSocketIOはなかったので、改めて今時の書き方を調査しておいて、自分テンプレートを更新しておこうと思い、今回はその備忘録ブログです。
Nodejsの旧バージョンでのエラーポイント
以前にNodejsのSocket.IOを学習がてら書いたブログは、
Node.jsを短期学習してみる #3「チャット」
ここで書いているコードを簡単にまとめると、次の通りです。
# 失敗するサーバーコード
var server = require("http").createServer(function(req, res) {...}).listen(8888);
var io = require("socket.io").listen(server);
# Errorメッセージ
% node old
/Users/yugeta/web/test/nodejs/socket/old.js:2
var io = require("socket.io").listen(server);
^
TypeError: require(...).listen is not a function
at Object.<anonymous> (/Users/yugeta/web/test/nodejs/socket/old.js:2:31)
at Module._compile (node:internal/modules/cjs/loader:1097:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
at node:internal/main/run_main_module:17:47
Node.js v17.4.0
上記を次の様にすると、サーバーエラーは無くなります。
# 改善後のサーバーコード
var server = require("http").createServer(function(req, res) {...}).listen(8888);
var io = require("socket.io")(server);
おわかりいただけただろうか?
違いは、socket.ioをURLをサーバーセットする、次の箇所だったんですね。
var io = require("socket.io").listen(server);
listenという命令がなくなったみたいなので、この記述があると、エラーになります。
ちなみに、今現在の各種バージョンは次の通りです。
$ node --version
v17.4.0
$ npm --version
8.3.1
$ npm list socket.io
socket@ /Users/yugeta/web/test/nodejs/socket
├── socket.io@4.5.1
└─┬ socketio@1.0.0
└── socket.io@1.7.4
今時のNodejsの書き方
とりあえず、サーバー側で安定したSocket.IOが立ち上がる様になったら、次はクライアント側も今時の書き方をしましょう。
そうはいっても、色々なサイトで書かれているのは、client側もnodejsで動かすことが前提で書かれており、apiライブラリ推進派のユゲタとしては、そういう使い方ではなく、ノーマルHTMLファイルで立ち上げても動作する仕組みとしてsocket.ioを使いたいんですよね。
とりあえず色々なサイトに書かれている通りにしても、"Access-Control-Allow-Origin"エラーで、うまくポーリングが永遠つながらずにコンソールでエラーを吐き続けます。
そして、四苦八苦すること、丸一日。
無事にサーバーとつながった記述が次の通りです。
# server.js
const socket = require('socket.io')
const port = 3301
const io = socket()
io.on('connection', socket => {
socket.emit('hello' , 'world')
socket.on('howdy',(arg)=>{
console.log(arg)
})
})
io.listen(port)
console.log(`Run ... (port : ${port})`);
# index.html
<script src='http://localhost:3301/socket.io/socket.io.js'></script>
<script type='module' src='client.js'></script>
<h1>Socket.io</h1>
# client.js
(()=>{
const port = 3301
const url = 'ws://localhost:'+ port
const socket = io(url , { transports : ['websocket'] });
socket.on('hello', (arg) => {
console.log(arg);
});
socket.emit('howdy' , 'stranger')
})()
簡単に解説
とりあえず、ポート番号を3301にセットしているんですが、好き勝手なポート番号に変えてもらっても動きます。
client.jsのurl指定で、wsプロトコルを指定しているのがポイントですね。httpやhttpsでも動くんですが、websoketプロトコル使う方がいい感じがするので、単純に使ってみました。
あと、htmlで、事前に"http://localhost:3301/socket.io/socket.io.js"このURLを読み込んでおくことを忘れない様にしましょう!
Access-Control-Allow-Originエラーで困っていた件に関しては、
const socket = io(url , { transports : ['websocket'] });
として、transportsというオプションを入れることで、エラーがなくなり、解消することができました。
いや〜奥が深い・・・
そして、socket.ioというかwebsocketにおけるややこしい、onイベントとemitイベントで、ちゃんとサーバーとクライアントの相互データやりとりが理解できたら、あとは、ゴリゴリと、コードを足していくだけですね。
最後に
Socket.IOは、慣れると細かな処理が書ける上、個人的に非常に扱いやすいライブラリなので、その特性を生かしたSPAツールを作ることが可能になります。
通常のwebサイトに面白い機能をつけたいと思ったら、必須のライブラリですね。
でも、サーバー負荷には気をつける様にしましょう。
あと、バランシングなども苦労すると思うので、そういう場合は、Redisなどとの連携で大規模アプリ構築にトライしてみるといいですね。
0 件のコメント:
コメントを投稿