Skip to content

多语言客户端实现

以下是各种编程语言的 WebSocket 客户端实现示例,用于连接和调用 iClick API。

提示

所有示例都实现了相同的功能:

  • WebSocket 连接和自动重连
  • 请求/响应匹配(基于 evtid
  • 超时处理
  • 二进制数据支持
  • 事件推送处理

注意

以下代码示例可能未经充分验证,仅供参考学习。在生产环境使用前,请务必进行充分的测试和验证。

javascript
const wserverPort = 23188
const wsevents = {}
let wsclient = null
let reconnectTimer = null

export function reconnect() {
    if( reconnectTimer || wsclient?.readyState === WebSocket.CONNECTING ){
        return
    }
    reconnectTimer = setTimeout(() => {
        console.log('API服务重连中...')
        connectServer().finally(() => reconnectTimer = null)
    }, 1000 * 3)
}

export function connectServer() {
    return new Promise((_resolve) => {
        
        if( wsclient ){
            return
        }

        wsclient = new WebSocket(`ws://127.0.0.1:${wserverPort}`)
        wsclient.binaryType = 'arraybuffer'

        wsclient.onopen = () => {
            console.log('API服务连接成功')
            _resolve()
        }

        wsclient.onmessage = (_message) => {
     
            let _payload = _message.data,
                _bindata = null

            if( typeof _payload === 'string' ){

                _payload = JSON.parse(_payload)

            }else{

                // 部分接口返回的是二进制数据,需要解析 [metaDataLength][metaData][binary]
                const _decoder = new TextDecoder('utf-8')   
                const _metaLength = _decoder.decode(_payload.slice(0, 6))
                                    _bindata = _payload.slice(6 + parseInt(_metaLength))
                                    _payload = JSON.parse(_decoder.decode(_payload.slice(6, 6 + parseInt(_metaLength))))
                _payload.data = _bindata
                _bindata = null
            }
            
            const _eventId = _payload.evtid
            const _event = wsevents[ _eventId ]
  
            if( _event ){

                if( _payload.type === 'error' ){
                    _event.reject(new Error(_payload.error))
                }else{
                    _event.resolve( _payload.data )
                }

                delete wsevents[ _eventId ]

            }else if( _payload.event ){

                //你可以根据不同语言派发事件
            }
        }
        
        wsclient.onclose = (code) => {

            wsclient = null
            console.log('API服务连接关闭:', code)
            reconnect()
        }
        
        wsclient.onerror = (err) => {
            console.error('API服务连接错误:', err)
        }
    })
}


export function apiInvoke(type, _params = {}, _timeout = 18) {

    return new Promise((resolve, reject) => {

        if( !wsclient || wsclient.readyState !== WebSocket.OPEN ){

            reject( new Error('API服务连接未就绪') )

        }else{

            const _eventId = Math.random().toString(36).substring(2, 12)
            const _payload = {
                ..._params,
                type,
                evtid: _eventId,
                timeout: _timeout
            }

            wsevents[_payload.evtid] = { resolve, reject }

            wsclient.send(JSON.stringify(_payload))

            if( _timeout > 0 ){
                setTimeout(() => {

                    reject(new Error(`API服务: ${_payload.evtid} Invoke Timeout !`))

                    delete wsevents[_payload.evtid]

                }, _timeout * 1000)
            }
        }
    })
}

// 使用示例
await connectServer()
const result = await apiInvoke('click', { x: 100, y: 200, deviceId: 'XXXXXXXXXX' })

下一步

  • 阅读更具体的 API 使用示例

商务合作:try.catch@foxmail.com