はじめに
去年、私自身がWebRTCハンズオン 本編を使用して、WebRTCの勉強をしていた時につまずいた部分で、今年研究室に入ってきた後輩も困っていたので、改めてエラーの原因を調べました。
発生した現象
エラーが発生した部分
ハンズオン資料のSTEP4 シグナリングサーバを使ってWebRTCをつなげようの部分で、送信用のクライアント端末からシグナリングサーバーにSDPを送信します。その後、シグナリングサーバーはSDPを受信用のクライアント端末に転送します。この転送されたSDPを受信用のクライアント端末が解析する際にエラーが発生します。
現象
受信用のクライアント端末で文字列をJSONとして解析する部分で、Uncaught SyntaxError: Unexpected token 'o', "[object Blob]" is not valid jsonというエラーが発生する。
このエラーは「[object Blob] という文字列が有効なJSON形式の文字列でない。」という意味です。[object Blob] というのはバイナリデータのBlobオブジェクトが文字列型にキャストされたデータを指します。
String(new Blob([0]))
//'[object Blob]'
要するに、JSON形式のテキストデータが届くはずのところにバイナリデータが届いてしまっているために発生するエラーです。
状況
WebSocketの通信をwiresharkを使用してキャプチャしたところ
- 送信用のクライアント端末 -> シグナリングサーバーはテキストデータとして送信されている
- シグナリングサーバー -> 受信用のクライアント端末はバイナリデータとして送信されている
対処方法
signaling.jsを下記のように書き換える。
"use strict";
const WebSocketServer = require("ws").Server;
const port = 3001;
const wsServer = new WebSocketServer({ port: port });
wsServer.on("connection", function (ws) {
console.log("-- websocket connected --");
ws.on("message", function (message, isBinary) {
wsServer.clients.forEach(function each(client) {
if (isSame(ws, client)) {
console.log("- skip sender -");
} else {
client.send(message, { binary: isBinary });
}
});
});
});
function isSame(ws1, ws2) {
// -- compare object --
return ws1 === ws2;
}
console.log("websocket server start. port=" + port);
原因
node.jsのWebSocketモジュールの仕様変更が原因で起こるエラーでした。
現在のWebSocket Serverは、データを受信する際、第一引数に受信したデータをバイナリデータとして、第二引数にバイナリデータであるかどうかのフラグをコールバック関数に渡します。
仕様変更前は、テキストメッセージを受信した際にWebSocket Serverが内部でUTF-8にデコードする動作を行っていたため、binary引数を指定する必要がありませんでした。現在はデコード処理が無駄とされており、binary引数を渡すことでデコードせずに文字列型のデータとして送信できるようになっています。
binary引数を省略すると、シグナリングサーバーはデータをバイナリデータとしてクライアントに送信してしまいます。その結果、受信用のクライアント端末は文字列型を想定していたところにBlobオブジェクトが届いてしまって、エラーが発生していました。