WebSocket (Socket.io) 连接错误 - 失败:连接在收到握手响应之前关闭

WebSocket (Socket.io) connection Error - failed: Connection closed before receiving a handshake response

我花了一整天的时间在网上找出错误的解决方案

WebSocket connection to 'wss://localhost/myapp/peerjs?key=peerjs&id=5c70da87-62c1-41dd-b1b1-e7aea5acc09b&token=j4n0nprnu6' failed: Connection closed before receiving a handshake response

我正在 express 服务器上开发这个 nodejs 应用程序。我的 express 服务器,我在其中初始化 PeerServer:

// Dependencies
const express = require('express')
const app = express()
const httpPort = process.env.PORT || 80
const httpsPort = 443
const { ExpressPeerServer } = require('peer')
const path = require('path')
const http = require('http')
const https = require('https')
const fs = require('fs')

// Certificate & credentials
const privateKey = fs.readFileSync(path.join(__dirname, 'certs', 'key.pem'))
const certificate = fs.readFileSync(path.join(__dirname, 'certs', 'cert.pem'))
const credentials = {
        key: privateKey,
        cert: certificate
}

const mainServer = http.createServer(app).listen(httpPort, () => { console.log('Main Server listening to port ' + httpPort) })
const httpsServer = https.createServer(credentials, app).listen(httpsPort, () => { console.log('Peer Server listening to port ' + httpsPort) })

const peerServer = ExpressPeerServer(mainServer, {
        debug: true,
        path: '/myapp'
})

//app.use('peerjs', peerServer)
app.use(peerServer)

const io = require('socket.io')(httpsServer)
const { v4: uuidV4 } = require('uuid')

app.set('view engine', 'ejs')
app.use(express.static('public'))

app.get('/', (req, res) => {
  res.redirect(`/${uuidV4()}`)
})

app.get('/:room', (req, res) => {
  res.render('room', { roomId: req.params.room })
  //console.log('Room Created / Joined')
})

io.on('connection', (socket) => {
    //console.log('IO Connectedd')
    socket.on('join-room', (roomId, userId) => {
        console.log(roomId, userId)
        socket.join(roomId)
        socket.to(roomId).emit('user-connected', userId)

        socket.on('disconnect', () => {
            socket.to(roomId).emit('user-disconnected', userId)
        })
    })
})

下面是我的客户端代码

const socket = io('/')
const videoGrid = document.getElementById('video-grid')
const myPeer = new Peer(undefined, {
    host: '/',
    port: '443',
    path: '/myapp'
})
const ownVideo = document.createElement('video') // Own Video
ownVideo.muted = true
const peers = {}
navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true
}).then(stream => {
    addVideoStream(ownVideo, stream)

    myPeer.on('call', call => { // On Receiving Other Persons Call
        call.answer(stream) // Send Video Stream On Answer
        const video = document.createElement('video')
        call.on('stream', userVideoStream => { // Send Back Video Stream On Stream
            addVideoStream(video, userVideoStream)
        })
    })

    socket.on('user-connected', userId => { // Allow Self To Be Connected To Others
        console.log('User Connected: ' + userId)
        connectToNewUser(userId, stream)
    })
})

socket.on('user-disconnected', userId => {
    if (peers[userId]) peers[userId].close()
})

myPeer.on('open', id => {
    socket.emit('join-room', ROOM_ID, id)
})

function connectToNewUser(userId, stream) {
    const call = myPeer.call(userId, stream) // We Connect To Other User
    const video = document.createElement('video')
    call.on('stream', userVideoStream => { // Other User Connects To Us
        addVideoStream(video, userVideoStream)
    })
    call.on('close', () => { // Other User Disconnects
        video.remove()
    })

    peers[userId] = call
}

function addVideoStream(video, stream) {
    video.srcObject = stream
    video.addEventListener('loadedmetadata', () => {
        video.play()
    })
    videoGrid.append(video)
}

我是 nodejs 的新手,在网上找不到任何解决方案。

请帮忙!!

您的代码需要重新安排,一旦完成,它在 W10、VSC 和 Chrome 版本 91.0.4472.164(官方构建)(64 位)上对我来说运行良好。包含我的工作代码比尝试解释每个更改更简单。我将在此处包含 script.js 和 server.js 文件(工作)以及 github here 中的整个代码工作区供任何人使用。我想强调的是,您确实想在等待任何承诺之前调用 peer.on('call'... 事件处理程序,以确保您的远程客户端在收到来自发起者客户端,这不是导致您询问的错误的问题的一部分。

客户端:

const socket = io('/')
const videoGrid = document.getElementById('video-grid')
let Peer = window.Peer;
const peer = new Peer({
    host: '/',
    path: '/peerjs',
    debug: 3,
    port: 80,
    secure: false,
});

console.log('***Created peer instance, userId: ' + peer.id)

// Function to obtain stream and then await until after it is obtained to go into video chat call and answer code. Critical to start the event listener ahead of everything to ensure not to miss an incoming call.

const ownVideo = document.createElement('video') // Own Video
ownVideo.muted = true
const peers = {}
// On Receiving Other Persons Call
peer.on("call", async (call) => {
    try {
        let stream = null;
        stream = await navigator.mediaDevices.getUserMedia({
            video: true,
            audio: true
        });
        call.answer(stream) // Send Video Stream On Answer
        const video = document.createElement('video');
        // Send Back Video Stream On Stream
        call.on('stream', userVideoStream => {
            addVideoStream(video, userVideoStream);
        });
    }
    catch (err) {
        /* handle the error */
        console.log('*** ERROR returning the stream: ' + err);
    }
});

    (async () => {
        try {
            let stream = null;
            stream = await navigator.mediaDevices.getUserMedia(
                {
                    audio: true,
                    video: true,
                });
            if (stream != undefined) {
                addVideoStream(ownVideo, stream);
                console.log('added own Video stream');
            } else {
                console.log('You can only access your audio/video media streams over https');
                alert('Sorry retry using https, for security reasons Google Media blocks access to your video stream over unsecure http connections');
            }
        } catch (err) {
            /* handle the error */
            console.log('*** ERROR returning the stream: ' + err);
            alert('Sorry retry using https, for security reasons Google Media blocks access to your video stream over unsecure http connections');
        }
    })();


socket.on('user-connected', userId => { // Allow Self To Be Connected To Others
    console.log('User Connected: ' + userId)
    navigator.mediaDevices.getUserMedia({
        video: true,
        audio: true
    }).then(stream => {
        connectToNewUser(userId, stream)
    })
})

socket.on('user-disconnected', userId => {
    if (peers[userId]) peers[userId].close()
})

peer.on('open', id => {
    socket.emit('join-room', ROOM_ID, id)
})

function connectToNewUser(userId, stream) {
    const call = peer.call(userId, stream) // We Connect To Other User
    const video = document.createElement('video')
    call.on('stream', userVideoStream => { // Other User Connects To Us
        addVideoStream(video, userVideoStream)
    })
    call.on('close', () => { // Other User Disconnects
        video.remove()
    })

    peers[userId] = call
}

function addVideoStream(video, stream) {
    video.srcObject = stream
    video.addEventListener('loadedmetadata', () => {
        video.play()
    })
    videoGrid.append(video)
}

服务器端:

// Dependencies
const express = require('express')
const app = express()
const httpPort = process.env.PORT || 80
const httpsPort = 443
const { ExpressPeerServer } = require('peer')
const path = require('path')
const http = require('http')
const https = require('https')
const fs = require('fs')
const certs = `C:/Users/spine/Documents/Personal Files/ArduinoData/packages/esp8266/hardware/esp8266/2.7.4/libraries/ESP8266WiFi/examples/BearSSL_Server/`


// Certificate & credentials
const privateKey = fs.readFileSync(path.join(certs, 'key.pem'))
const certificate = fs.readFileSync(path.join(certs, 'cert.pem'))
const credentials = {
        key: privateKey,
        cert: certificate
}

const mainServer = http.createServer(app).listen(httpPort, () => { console.log('Main Server listening to port ' + httpPort) })
const httpsServer = https.createServer(credentials, app).listen(httpsPort, () => { console.log('Peer Server listening to port ' + httpsPort) })

const peerServer = ExpressPeerServer(mainServer, {
        debug: true,
        ssl: {},
})

app.use('/peerjs', peerServer)
// app.use(peerServer)

const io = require('socket.io')(httpsServer,{
// const io = require('socket.io')(mainServer, {
  cors: {
      origin: "*",
  },
});
const { v4: uuidV4 } = require('uuid')

app.set('view engine', 'ejs')
app.use(express.static('public'))

app.get('/', (req, res) => {
  res.redirect(`/${uuidV4()}`)
})

app.get('/:room', (req, res) => {
  res.render('room', { roomId: req.params.room })
  //console.log('Room Created / Joined')
})

io.on('connection', (socket) => {
    //console.log('IO Connectedd')
    socket.on('join-room', (roomId, userId) => {
        console.log(roomId, userId)
        socket.join(roomId)
        socket.to(roomId).emit('user-connected', userId)

        socket.on('disconnect', () => {
            socket.to(roomId).emit('user-disconnected', userId)
        })
    })
})

我在服务器端使用了以下鳕鱼。虽然我只能通过 SSL 让它工作。

const express = require('express')
const app = express()
const httpPort = process.env.PORT || 80
const httpsPort = 443
const { ExpressPeerServer } = require('peer')
const path = require('path')
const http = require('http')
const https = require('https')
const fs = require('fs')

// Certificate & credentials
const privateKey = fs.readFileSync(path.join(__dirname, 'certs', 'key.pem'))
const certificate = fs.readFileSync(path.join(__dirname, 'certs', 'cert.pem'))
const credentials = {
    key: privateKey,
    cert: certificate
}

const httpsServer = https.createServer(credentials, app).listen(httpsPort, () => { console.log('Peer Server listening to port ' + httpsPort) })

const peerServer = ExpressPeerServer(httpsServer, {
        debug: true,
        path: '/myapp'
})

app.use(peerServer)

const io = require('socket.io')(httpsServer, {
   forceNew: true,
   transports: ["polling"],
})
const { v4: uuidV4 } = require('uuid')

app.set('view engine', 'ejs')
app.use(express.static('public'))

app.get('/', (req, res) => {
  res.redirect(`/${uuidV4()}`)
})

app.get('/:room', (req, res) => {
  res.render('room', { roomId: req.params.room })
})

io.on('connection', (socket) => {
    socket.on('join-room', (roomId, userId) => {
        socket.join(roomId)
        socket.broadcast.to(roomId).emit('user-connected', userId)

        socket.on('disconnect', () => {
            socket.broadcast.to(roomId).emit('user-disconnected', userId)
        })
        socket.on('text-message', message => {
            socket.broadcast.to(roomId).emit('text-message-received', message)
        })
        socket.on('system-stream-updated', remoteUserId => {
            socket.broadcast.to(roomId).emit('new-remote-stream', remoteUserId)
        })
    })
})