NodejsのSocket.IOを再学習(開発環境でエラーを出さないために)

2022年6月2日

テクノロジー

eyecatch 技術が陳腐化するのは、まるで正月に食べようと思っていたお餅を、正月すぎてみたら、カビが生えてた様なもんだな、と考えた、ユゲタです。 なんだか技術って陳腐化しちゃうので、賞味期限に気をつけなければいけないのは、食べ物だけじゃないという話です。 今回の焦点は、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などとの連携で大規模アプリ構築にトライしてみるといいですね。

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。