为何调用encryptClient()后Socket.IO陷入无限递归循环?
解决Socket.IO添加encryptClient()后出现的递归溢出错误
未将encryptClient()函数加入emit方法前,Socket.IO运行完全正常,但添加后执行时触发以下递归溢出错误并陷入循环:
Uncaught InternalError: too much recursion isBinary is-binary.js:20 hasBinary is-binary.js:36 hasBinary is-binary.js:45 hasBinary is-binary.js:45 hasBinary is-binary.js:45 hasBinary is-binary.js:45 hasBinary is-binary.js:45 hasBinary is-binary.js:45 hasBinary is-binary.js:45 hasBinary is-binary.js:45 hasBinary is-binary.js:45
相关代码
index.html
<script > var socket = io(); var messages = document.getElementById('messages'); var form = document.getElementById('form'); var input = document.getElementById('input'); form.addEventListener('submit', function (e) { e.preventDefault(); // var cipherText = encryptClient(); if (input.value) { socket.emit('chat message', encryptClient()); input.value = ''; console.log("encrypted message sent") } }); socket.on('chat message', function (msg) { var item = document.createElement('li'); item.textContent = msg; messages.appendChild(item); window.scrollTo(0, document.body.scrollHeight); }); </script>
index.js
const cwd = process.cwd(); const express = require(cwd + '/node_modules/express'); const app = express(); const http = require('http').Server(app); const io = require('socket.io')(http); const port = process.env.PORT || 3000; app.use(express.static(cwd)); app.get('/', (req, res) => { res.sendFile('/index.html'); }); io.on('connection', (socket) => { socket.on('chat message', msg => { io.emit('chat message', msg); }); }); http.listen(port, () => { console.log(`Socket.IO server running at http://localhost:${port}/`); });
ClientEncrypt.js(已用browserify打包)
window.encryptClient = () => { //document.getElementById("welcomeText").innerHTML = "poop"; console.log("started"); var CryptoJS = require("crypto-js"); //var plainText = "Test"; var plainText = document.getElementById("input").value; if(plainText == ''){ console.log("Error, encrypt called while empty") return null; } var secretKey = "zdvB5oTxhVjxuFLBd8UJOOvNH3yton8POErBOza6n0z5OSKrNwniqA7mD5SNFTTZ"; var cipherText = CryptoJS.AES.encrypt(plainText, secretKey); console.log("Encrypted Message: " + cipherText); //document.getElementById("welcomeText").innerHTML = cipherText; var decryptedPlainText = CryptoJS.AES.decrypt(cipherText, secretKey); console.log("Decrypted Message: " + decryptedPlainText.toString(CryptoJS.enc.Utf8)); return cipherText; }
问题原因与解决方案
原因
CryptoJS.AES.encrypt()返回的不是普通字符串,而是一个包含循环引用的CryptoJS对象。Socket.IO在序列化这个对象时,会递归遍历其内部属性,触发无限递归,最终导致栈溢出错误。
解决步骤
- 修改加密函数的返回值:在
ClientEncrypt.js中,将返回的cipherText转为字符串格式:
// 替换原return语句 return cipherText.toString();
- 接收端处理(可选):如果需要在客户端解密消息,接收时将字符串转回CryptoJS可处理的格式即可:
socket.on('chat message', function (msg) { // 解密示例(需确保客户端有CryptoJS依赖) var secretKey = "zdvB5oTxhVjxuFLBd8UJOOvNH3yton8POErBOza6n0z5OSKrNwniqA7mD5SNFTTZ"; var decrypted = CryptoJS.AES.decrypt(msg, secretKey); var plainText = decrypted.toString(CryptoJS.enc.Utf8); var item = document.createElement('li'); item.textContent = plainText; // 或直接显示加密后的msg messages.appendChild(item); window.scrollTo(0, document.body.scrollHeight); });
这样修改后,Socket.IO发送的是普通字符串,不会触发递归遍历对象的逻辑,即可解决递归溢出问题。
内容的提问来源于stack exchange,提问作者BHughes
相关产品推荐
相关产品推荐

