【仅供内部供应商使用,不提供对外解答和培训】

Page tree

【仅供内部供应商使用,不提供对外解答和培训】

Skip to end of metadata
Go to start of metadata

目的:

有一些场景下需要websoket实时通知或者互动,特别是跨屏时,所以我尝试使用fr原生的websocket来解决一些业务场景,本文主要是记录我的尝试和分析,不一定是官方的效果。

受限fr的websocket是基于socket.io 2.0版本实现的,通过分析

com/fr/web/socketio/SocketIOServerFactory.class

com/fr/third/socketio/SocketIOServer.class

两个文件可以知道fr的websocket的启动和使用过程(服务器端),首先需要提到的是fr使用websocket实际上是基于namespace的,默认是“/system”命名空间,在后台发送消息给前端时,如果是自己写的js自己去连接的需要注意命名空间的隔离。

使用fr的websocket有一个很方便的地方在于不用我们自己去处理clients的保存,假如我们自己实现,当集群环境的时候这个clients保存就不是很方便了,所以推荐直接用fr原生的websocket。


前端使用:


前端如果在决策平台就不需要在引入socket.io的库了,如果是自己写html建议引入下面这个库,不要自己去网上下载,容易不兼容。

<script type="text/javascript"
src="${fineServletURL}/file?path=/com/fr/web/socketio/dist/socket.io.js&type=plain&parser=plain"></script>
因为fr自己使用websocket是在决策平台使用的,所以我分析js部分注册websocket是在

com/fr/web/ui/materials.min.js

/**
        * 初始化socket连接
        * @param {*} options 连接socket的参数
        * @param {*} cb 返回连接结果
        */
        initSocket: function (options, cb) {
            var ports = options.webSocketPort, portIndex = 0, isInit = true;
            var socket = null, callback = BI.isFunction(cb) ? cb : BI.emptyFn;

            function reconnect (v) {
                if (v >= BI.size(ports)) {
                    isInit = false;
                    callback("fail");
                    return;
                }
                socket.io.uri = options.requestUrl + ":" + ports[v] + options.webSocketNameSpace;
                socket.io.connect();
                socket.connect();
            }

            try {
                socket = io.connect(options.requestUrl + ":" + ports[portIndex] + options.webSocketNameSpace, BI.extend({
                    query: options.query,
                    path: options.webSocketContextName
                }, options.options));

                // 监听到失败或者超时时使用下一个端口, 初始化成功之后无效
                socket.on("connect_error", function () {
                    isInit && reconnect(++portIndex);
                });

                socket.on("connect", function () {
                    isInit = false;
                    callback("success");
                });
                return socket;
            } catch (e) {
                throw new Error(e);
            }
        }
    });

实际上上面的代码是帮忙处理了链接和重试的工作。


在业务注册的时候需要提供token 以供认证,这里的token就是fr的 fine_auth_token 使用方法如下:

var token = "${fine_auth_token}";
 
    var t = window.location.protocol + "//" + window.location.hostname
    var config = BI.extend({
        requestUrl: t,
        query: {
            token: token
        }
    }, {
        webSocketContextName: "/socket.io",
        webSocketNameSpace: "/system",
        webSocketPort: [38888, 39888, 38889],
        webSocketProtocol: "plain"
    });
//这个socket对象就可以做socket.io的操作了
    var socket = window.scocket = BI.initSocket(config, function (e) {
        console.info("连接socket 成功");
        if (socket) {
            socket.emit("joinDP","success")
            console.info("发送加入房间 成功");
        }
    })
使用了上面的代码注册之后会获得一个socket对象,这个对象就是socket.io的操作对象了,可以on 接收消息,可以emit 发送消息。但是这里需要注意的是,这样获得的对象默认namespace就是/system.从后台发消息需要注意namespace不要弄错了。

好了经过上面两个代码前端算是能连上websocket了,那么后台怎么广播消息呢?
就在最上面我提到两个类文件,实际上我们后台代码主要操作的也主要是这两个类,通过下面代码就可以给前端发消息了。

SocketIOServerFactory.getBroadcastOperations().sendEvent("消息名", "消息内容");
注意这个消息名,需要前端的socket对象用on关注这个消息才可以收到例如

socket.on("消息名",function(msg){
    alert("收到"+msg)
})

这样就能把服务器或者其他人发的消息打印出来了。

最后一个问题,后台如何接收和处理前端发送的消息?

这里要用到 SocketIOServer 这个实例,通过这个实例的 addEventListener 函数来关注前端发送到后台的消息,我这里给大家举一个例子:

socketIOServer.getNamespace("/system").addEventListener("joinDP", String.class, (client, data, ackReq) -> {
     FineLoggerFactory.getLogger().info("收到用户加入事件:{}", client);
});

我们通过socketIOServer 的getNamespace 获取/system的命名空间,在这个命名空间中添加一个joinDP的事件监听,第二个参数String.class标识监听前端发送过来的内容的类型是字符串,第三个参数是一个回调函数当收到前端的消息时会触发

这个函数,我在这个函数中做了一个打印日志的工作,其实大家也可以通过 SocketIOServerFactory.getBroadcastOperations().sendEvent("事件名",data); 将这个事件广播出去。或者通过 找到 SocketIOClient 去调用每一个client的发送方法

去发送消息。


最后遗留的问题:


1.是否fr提供了用户到clients的映射关系?

2.目前这个websocket只能用token去认证,并且只能一个网页连接,另一个网页再连接前一个就会收不到消息,怀疑是clients注册的时候给挤掉了??

麻烦官方的大佬能给一下解答和帮助















  • No labels