美文网首页前端开发那些事儿杂文类
vue中使用vue-socket.io的一些心得、踩坑记录

vue中使用vue-socket.io的一些心得、踩坑记录

作者: 隔壁老樊啊 | 来源:发表于2020-06-20 16:47 被阅读0次

    前言

    vue项目中有使用到socket长连接,之前一直都是都是使用vue-socke.io[github地址],但最近在使用时,出了一些莫名奇妙的bug,也是为此掉了不少头发,最后还是解决了。关于socket相关内容介绍以及使用场景,这里不会做太多介绍(主要是懒),可以翻看其他文章。本文主要介绍如何使用,以及再使用时需要注意一些什么。关于文章中使用的代码,我放上github地址。前端小鸟一枚,立誓要成为前端菜鸟,不足地方留言指出,小子谢过。

    安装

    这里我们安装vue.socket.io模块和socket.io-client模块,也可以不用socket.io-client模块,请往下看。

    cnpm i vue-socket.io -S
    cnpm i socket.io-client -S
    
    yarn vue-socket.io
    yarn i socket.io-client
    

    vue 客户端使用

    • 使用socket.io-client连接
    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'
    import store from './store'
    import VueSocketIO from 'vue-socket.io'
    import SocketIO from "socket.io-client"
    
    Vue.config.productionTip = false
    
    // socket 连接参数
    const socketOptions = {
      autoConnect: false,       // 自动连接     这里为我项目需求  需要在指定情况下才连接socket
    }
    
    // 注册
    Vue.use(
      new VueSocketIO({
        debug: true ,   // debug调试,生产建议关闭
        connection: SocketIO("127.0.0.1:1024", socketOptions),
        store,          // 如果没有使用到store可以不用写
      })
    )
    
    
    new Vue({
      // 这里为全局监听socket事件消息,监听函数这里只写了一点,其实很有很多事件。
      sockets: {
        connecting() {
          console.log('正在连接')
        },
        disconnect() {
          console.log("Socket 断开");
        },
        connect_failed() {
          cosnole.log('连接失败')
        },
        connect() {
          console.log('socket connected')
        }
      },
      router,
      store,
      render: h => h(App)
    }).$mount('#app')
    
    • 字符串连接

      如果是正常使用,项目启动就连接socket,可以不需要加载socket.io-client模块,直接使用。

    // 注册
    Vue.use(
      new VueSocketIO({
        debug: true ,   // debug调试,生产建议关闭
        connection: 127.0.0.1:1024,
        store,          // 如果没有使用到store可以不用写
      })
    )
    
    • 组件中使用
    
    <template>
      <div id="app">
        <div id="nav">
          <button @click="connect">连接socket</button>
          <button @click="sendMessage">发送数据</button>
        </div>
      </div>
    </template>
    
    
    <script>
    export default {
      data() {
        return {
    
        }
      },
    
      methods:{
    
        // 连接socket
        connect() {
    
          this.$socket.open()       // 开始连接socket
         
          // 订阅事件
          this.sockets.subscribe('welcome', data => {
            console.log('welcome data ', data)
          }) 
          
        },
    
        // 发送消息
        sendMessage() {
          
          this.$socket.emit('hello', '这里是客户端')
    
        }
    
    
    
      },
    
      sockets:{
        // 
        welcome: data => {
          console.log('welcome data ', data)
        }
    
      }
    }
    </script>
    
    

    客户端使用总结

    客户端自带监听事件

    • connect:连接成功
    • connecting:正在连接
    • disconnect:断开连接
    • connect_failed:连接失败
    • error:错误发生,并且无法被其他事件类型所处理
    • reconnect_failed:重连失败
    • reconnect:成功重连
    • reconnecting:正在重连

    监听自定义事件

    • 全局监听
    sockets:{
        welcome: data => {
            console.log('welcome data', data)
        }
    }
    
    • 组件内监听
    this.sockets.subscribe('welcome', data => {
        console.log('welcome', data)
    })
    

    发送消息

    注意:监听用的是this.sockets,发送消息是this.$socket,不要弄混。

    this.$socket.emit('hello', '这里是客户端')
    

    关于跨域问题

    socket会存在跨域问题,之前看文章又说到在vue.config.js中配置代理,差不多和后台接口代理配置一样,但我试过好像没啥鸟用,如果有知道的同学麻烦留言告诉一声,实际项目中的解决方式还是后端配置跨域问题。

    服务端使用

    这里为啥要讲服务端使用,主要是为了让同学更好的体验socket,其次是为了引出后面的bug,也是一个扩展知识把,是不是觉得自己赚了😄。本地开启socket服务可以更好的进行调试。服务端主要还是使用node,毕竟咱也不会java、python....,这里以及配置了socket跨域。

    /*
     * @Descripttion: 
     * @version: 
     * @Author: fanliu
     * @Date: 2020-06-19 18:22
     * @LastEditors: fanliu
     * @LastEditTime: 2020-06-19 18:30
     */
    
    var http = require('http');
    var io = require('socket.io');
    
    // 创建server服务
    var server = http.createServer(function (req, res) {
    
      var headers = {};
      headers["Access-Control-Allow-Origin"] = "*";
      headers["Access-Control-Allow-Methods"] = "POST, GET, PUT, DELETE, OPTIONS";
      headers["Access-Control-Allow-Credentials"] = true;
      headers["Access-Control-Max-Age"] = '86400'; // 24 hours
      headers["Access-Control-Allow-Headers"] = "X-Requested-With, Access-Control-Allow-Origin, X-HTTP-Method-Override, Content-Type, Authorization, Accept";
      res.writeHead(200, headers);
      res.end();
    });
    
    // 启动服务器  监听 1024 端口
    server.listen(1024,function() {
        console.log('server runing at 127.0.0.1:1024')
    })
    
    // 启动socket服务
    var socket = io.listen(server, {origins: '*:*'});
    
    // 监听客户端连接
    socket.on('connection',function(socket) {
        console.log('客户端有连接')
        
        // 监听客户端断开
        socket.on('disconnect', () => {
            console.log('客户端断开')
        })
        
        // 给客户端发送消息
        socket.emit('welcome','欢迎连接socket')
        
            // 监听客户端消息
            socket.on('hello', data => {
                console.log('接收客户端发送数据', data)
            })
    
    });
    
    

    服务端总结

    服务端接收和发送消息和客户端对调的,客户端emit发送消息,那么服务端这里就要on监听客户端发送的消息,服务的发送同理。

    踩坑

    订阅事件记得要取消

    socket主要还是用来写聊天室,加入socket房间后要订阅房间内所有的聊天内容,这时如果没有取消之前的订阅事件,下次进入会多次订阅消息。也就是别人只发一条消息,你这边接收到的却是两条甚至多条。哪如何取消订阅呢,我的处理方式是在离开当前聊天页面后,自动取消之前所有的订阅事件。

        beforeDestroy() {
            this.sockets.unsubscribe(eventName)
        }
    

    同理,如果是有指定页面才加入socket房间,退出页面时也要记得关闭socket连接。比如你在created中开始连接socket,在beforeDestroy要记得关闭socket,不然下次进入也会连接socket。

    created() {
        this.$socket.open()
        // 查看socket是否连接成功
        this.$socket.connected
    }
    beforeDestroy() {
        this.$socket.close()
    }
    

    Type Error: this.sockets.subscribe is not a function

    这是我最近遇到的问题,原本以为是自己的this指向有问题,然后从到尾查遍了整个逻辑this,发现并不是这个问题。

    image

    在打印this.sockets之后我发现问题

    image
    subscribe订阅事件并没有直接存在,而是某个对象的属性,于是尝试了一下this.sockets.listenner.subscribe发现能用了。

    你以为这就结束了???接着我又发现问题

      sockets:{
    
        welcome: data => {
          console.log('welcome data ', data)
        }
    
      }
    

    并且订阅的事件中,socket日志显示component: undefined没有看到数据

    全局的订阅事件没有生效,并且socket自带的连接事件也没有启动打印。我直接傻了😢,之前使用的时候还没有这些问题,百度一大堆无果后,开始像官方求助。于是找到了问题。
    Vue-Socket.io: #connect subscribe, component: undefined

    image

    大概的意思是说,出现问题的都是3.0.9的版本,将版本后可以解决这个问题。这也是我为啥要把socket服务端写进了的原因。自己本地写了一个小demo后,还真的是版本的问题,随后就有了这篇文章。

    总结

    同学们在使用vue-socket.io时要注意一下版本,现在的3.0.9多多少少会出现问题,可以选择3.0.7版本。这个可以使用文章开头我的测试demo进行查看,socket服务代码也在项目中。
    第一次在掘金中发表文章,表达有错误的地方还请多多谅解,之后也会发布更多前端技术文章,还请多多关注。

    相关文章

      网友评论

        本文标题:vue中使用vue-socket.io的一些心得、踩坑记录

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