小程序API wx.connectSocket() 连接WebSocket错误

发布于 2022-09-11 19:55:30 字数 4550 浏览 12 评论 0

console:WebSocket connection to 'wss://localhost:5757/api/tunnel' failed: Error in connection establishment: net::ERR_CONNECTION_CLOSED

client

this.socketTask = wx.connectSocket({
    url: 'wss://localhost:5757/api/tunnel',
})

server
route

// GET  用来响应请求信道地址的
router.get('/tunnel', controllers.tunnel.get)
// POST 用来处理信道传递过来的消息
router.post('/tunnel', controllers.tunnel.post)

controllers

const { tunnel } = require('../qcloud')
const debug = require('debug')('koa-weapp-demo')

/**
 * 这里实现一个简单的聊天室
 * userMap 为 tunnelId 和 用户信息的映射
 * 实际使用请使用数据库存储
 */
const userMap = {}

// 保存 当前已连接的 WebSocket 信道ID列表
const connectedTunnelIds = []

/**
 * 调用 tunnel.broadcast() 进行广播
 * @param  {String} type    消息类型
 * @param  {String} content 消息内容
 */
const $broadcast = (type, content) => {
    tunnel.broadcast(connectedTunnelIds, type, content)
        .then(result => {
            const invalidTunnelIds = result.data && result.data.invalidTunnelIds || []

            if (invalidTunnelIds.length) {
                console.log('检测到无效的信道 IDs =>', invalidTunnelIds)

                // 从 userMap 和 connectedTunnelIds 中将无效的信道记录移除
                invalidTunnelIds.forEach(tunnelId => {
                    delete userMap[tunnelId]

                    const index = connectedTunnelIds.indexOf(tunnelId)
                    if (~index) {
                        connectedTunnelIds.splice(index, 1)
                    }
                })
            }
        })
}

/**
 * 调用 TunnelService.closeTunnel() 关闭信道
 * @param  {String} tunnelId 信道ID
 */
const $close = (tunnelId) => {
    tunnel.closeTunnel(tunnelId)
}

/**
 * 实现 onConnect 方法
 * 在客户端成功连接 WebSocket 信道服务之后会调用该方法,
 * 此时通知所有其它在线的用户当前总人数以及刚加入的用户是谁
 */
function onConnect (tunnelId) {
    console.log(`[onConnect] =>`, { tunnelId })

    if (tunnelId in userMap) {
        connectedTunnelIds.push(tunnelId)

        $broadcast('people', {
            'total': connectedTunnelIds.length,
            'enter': userMap[tunnelId]
        })
    } else {
        console.log(`Unknown tunnelId(${tunnelId}) was connectd, close it`)
        $close(tunnelId)
    }
}

/**
 * 实现 onMessage 方法
 * 客户端推送消息到 WebSocket 信道服务器上后,会调用该方法,此时可以处理信道的消息。
 * 在本示例,我们处理 `speak` 类型的消息,该消息表示有用户发言。
 * 我们把这个发言的信息广播到所有在线的 WebSocket 信道上
 */
function onMessage (tunnelId, type, content) {
    console.log(`[onMessage] =>`, { tunnelId, type, content })

    switch (type) {
        case 'speak':
            if (tunnelId in userMap) {
                $broadcast('speak', {
                    'who': userMap[tunnelId],
                    'word': content.word
                })
            } else {
                $close(tunnelId)
            }
            break

        default:
            break
    }
}

/**
 * 实现 onClose 方法
 * 客户端关闭 WebSocket 信道或者被信道服务器判断为已断开后,
 * 会调用该方法,此时可以进行清理及通知操作
 */
function onClose (tunnelId) {
    console.log(`[onClose] =>`, { tunnelId })

    if (!(tunnelId in userMap)) {
        console.log(`[onClose][Invalid TunnelId]=>`, tunnelId)
        $close(tunnelId)
        return
    }

    const leaveUser = userMap[tunnelId]
    delete userMap[tunnelId]

    const index = connectedTunnelIds.indexOf(tunnelId)
    if (~index) {
        connectedTunnelIds.splice(index, 1)
    }

    // 聊天室没有人了(即无信道ID)不再需要广播消息
    if (connectedTunnelIds.length > 0) {
        $broadcast('people', {
            'total': connectedTunnelIds.length,
            'leave': leaveUser
        })
    }
}

module.exports = {
    // 小程序请求 websocket 地址
    get: async ctx => {
        const data = await tunnel.getTunnelUrl(ctx.req)
        console.log(22222222222222222, data)
        const tunnelInfo = data.tunnel

        userMap[tunnelInfo.tunnelId] = data.userinfo

        ctx.state.data = tunnelInfo
    },

    // 信道将信息传输过来的时候
    post: async ctx => {
        const packet = await tunnel.onTunnelMessage(ctx.request.body)

        debug('Tunnel recive a package: %o', packet)

        switch (packet.type) {
            case 'connect':
                onConnect(packet.tunnelId)
                break
            case 'message':
                onMessage(packet.tunnelId, packet.content.messageType, packet.content.messageContent)
                break
            case 'close':
                onClose(packet.tunnelId)
                break
        }
    }

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文