美文网首页前端开发那些事
聊天室开发过程——记一个淘宝美工前端,后端一起来。

聊天室开发过程——记一个淘宝美工前端,后端一起来。

作者: 吴孝青 | 来源:发表于2018-11-12 00:31 被阅读11次

    服务端

    服务端使用基于PHP的Workerman 里面的GatewayWorker,虚拟主机好像不能使用。
    GatewayWorker的好处是可以客户端ID、用户ID、用户组为单位处理业务,而且有SESSION缓存功能,还可以在普通页面中调用,不同端口间通信。
    官方有集成的数据库连接类,和TP差不多,可以连等、事务、查询等。

    客户端

    使用VUE编写(对于数据处理,JQ真心不行),因为是按移动端填写的,所以用的是有赞的Vant,这个组件其实是商城的组件。
    刚开始想的是写成一个页面,然后不同组件调用。但后来发现不方便,所以引入了Vuex和Vue-routes。主要分成用户列表、用户私聊、用户群聊(暂时只实现大群聊天)、用户页面。因为网站有用户注册登录页面,所以用户页面纯是好看。

    开发经过

    工具

    1. 服务端
      -- 基本是GatewayWorker,自己写的代码不到100行(包含注释)。
    2. 客户端
      -- Vue Vant Vuex Vue-routes我是直接用的CDN,虽然开发我是用的NODE,但页面中我直接引入CDN,这样打包的JS文件小到想不到合计不到30K。
      -- 自己写的UI实在是不规范。不过个人认为比很多所谓专业的都写的好,至少功能实现了。
      -- 页面的东西不多,加载也算快。

    响应原理

    因为客户端运行过程中,WebSocket运行中能响应的只有function onMessage(client_id,message),所以一切业务逻辑都在这里面。
    这个方法里是把所有响应封装成类。而传入中把类名和方法名传处,再到类里面自动调用。

    客户端发送
    let  tpl={
      module:'ChatService',
      action:'getUserInfo',
      data:{
        uid:uid,
        client_id:client_id
      }
    };
    this.ws.send(JSON.stringify(tpl));
    
    服务端接收

    传入的是发送客户端的ID,数据,和数据库实例

       /**
        * 当客户端发来消息时触发
        * @param int $client_id 连接id
        * @param mixed $message 具体消息
        */
        public static function onMessage($client_id, $message)
        {
            $data=json_decode($message,true);
            if(!empty($data['module']) && !empty($data['action'])){
                $class='\\Workerman\\Service\\'.$data['module'];
                $class::{$data['action']}($client_id,$data['data'],self::$db);
            }
        }
    
    客户接收消息
    ws.onmessage= (e)=> {
        let obj,fn,raw;
        //这里很重要,服务端会发送一些异常数据,一定要过滤
        if(typeof e.data =='string' &&  e.data.substring(0,1)=='{' ){
            //这里过滤一下PHP转码时的一些空格 
            raw = e.data.replace(/\\([^u])/g, '$1');
            //console.log(e.data);
            obj=JSON.parse(raw);
            fn='receive'+obj.type;//取得函数名
            this[fn](obj);
        }
    }
    

    用户确定

    首先是在用最外面定义window.userInfo,包括 用户ID、用户昵称、用户名、用户头像、和session_id。如果是没有登录的用户,用户昵称会随机生成。头像为默认。因为每个用户在GatewayWorker中会对应一个UID,对于有用户ID的就用ID,没有用户ID的用session_id。这样注册用户可以在不同设备登录。但最大只能登录3台。
    在连接一建立,时就发送用户信息,服务端响应,并绑定用户的$_SESSION信息,并分配UID。这里如果从安全来讲,还要有一个登录令牌数据库较验的。
    在客户端发送数据后,服务端接收到数据会向所有用户发送用户上线消息。所以客户端还有一个收到某个用户上线的消息。

    客户端用户上线发送
    let tpl={
        module:'ChatService',
        action:'onOpen',
        data:{ userInfo:this.userInfo }
    };
    ws.send(JSON.stringify(tpl));
    
    服务端收到后确定UID,踢掉3个以上客户端,并发布用户上线消息
    public static function onOpen($client_id,$data ,$db)
    {
        $data['state']='Login';
        $data['type']='Login';
        $uid=!empty($data['userInfo']['id'])?$data['userInfo']['id']:$data['userInfo']['session_id'];
        $_SESSION['userInfo']=$data['userInfo'];
        $arr=Gateway::getClientIdByUid($uid);
        if(count($arr)>2){
            Gateway::closeClient($arr[0]);
        }
        Gateway::bindUid($client_id,$uid);
        Gateway::joinGroup($client_id, self::$group);
        Gateway::sendToGroup(self::$group,json_encode($data,true));
    }
    
    客户端收到上线消息处理

    用户上线后,把用户上线的对像加入到用户数组中。再对用户数组处理,得到用户列表。

    receiveLogin(obj){
        this.$store.commit('userListAdd',obj.userInfo);
    },
    

    取得在线用户列表

    初始用户登录后,或是登录一段时间后,要刷新用户列表。都采用的是,传入值里定义操作类、操作方法。

    私聊

    就是服务端将信息发送给指定UID,这里发送私聊是在子页面上,而接收私聊是在App.vue,父子组件间传递信息好实现,但不同页面间传递就不好实现。这里就用到了广播
    将所有私聊消息放到Vuex里,以数组的型式存放。到聊在窗口时,对数组过滤。

    对话框中对自己说的话进行了左右浮动设置

    判断消息是否是自己发出,然后对消息框进行左右浮动。

    新消息提示

    开发前觉得很难,开发中不知怎么的就想到了将消息ID放到一个数组,对话页面离开时将数组中对应ID全删除。在用户列表页面统计每个ID有几条信息。

    群聊

    群聊比较简单,是最基本的聊天室功能,暂时没有设计新建群和小群聊天。这次基本没有用到数据库,主要没用到数据库,后面考虑将聊天记录功能加上。用户添加好友的功能加上。

    总结

    踩坑

    1. 一直报JSON错误。因为没有看过GatewayWorker源码,可能服务端会推送一些不知名数据过来,所以对接收数据进行过滤。开始还以为是PHP里面数组转字符串时错误造成的。
    2. 对于vue的计算属性computed。在私聊开发过程中,想的时收到私聊信息后,将信息以‘masssge’:{“用户1”:[ 记录1,记录2,……],“用户2”:[ 记录1,记录2,……]}的型式方到vuex里,再到页面中取 对应用户的值,结果vuex里面更新了,到页面的计算属性中没有更新。计算属性中只是对massage监听,而他里面的“用户”的数组改变并不会影响massage。开发的过程中就有想到这一点,没有百度就找到答案了。
    3. 新消息自动下滑。还好没有走什么弯路,开发前还想的是引入什么框架或是NPM找个轮子
      ,用到了scrollIntoView(false);这个方法。当有消息增加时,在updated()里添加一次下滑到底部。

    心得

    1. 没有以前的那种什么都要做到无比优化的完美主义了,先实现再优化,前几天看到群里,一个码农说,他们老板在一个还没有写好的项目中不让用JQ的瀑布流插件,原因是JQ太耗性能了,怕手机上打开慢,在群里问原生瀑布流写法。这个聊天室我是先实现功能,再想着优化流程,要不然进行不下去。

    结束语

    写到最后了才附上聊天室地址。
    手机打开效果好,地址
    服务端地址:码云
    客户端:码云
    这个聊天室稍加改造可以成为客服工具,下一步准备写一个手机摇一摇比赛的项目。

    相关文章

      网友评论

        本文标题:聊天室开发过程——记一个淘宝美工前端,后端一起来。

        本文链接:https://www.haomeiwen.com/subject/ftuffqtx.html