socket.io-client
重要事情要放在最前面说
如果你用socket.io系列的包,但是疯狂报404错误。
那么你需要检查前后端是否都使用了socket.io系列的包去完成websocket通信!!!
那么你需要检查前后端是否都使用了socket.io系列的包去完成websocket通信!!!
那么你需要检查前后端是否都使用了socket.io系列的包去完成websocket通信!!!
-
最近在公司的项目里需要用到websocket通信。于是找到了socket.io-client库用于websocket通信。这让我调试了一天也没连上后端开启的websocket。但是用原生websocket去实现又可以正常和后端进行通信。
-
我发现一个socket.io-client的一个坑点就是前后端要商量好都得使用他们开发的包去进行通信。比如后端是nodeJs,前段用了socket.io-client后端也得使用socket.io-client。如果后端是java,问题不大,他们还开发了socket.io-client-java去配套使用。
-
有人就会有疑问了?websocket应该与库无关,也就是前后端各自开启websocket实现通信实际应该是互不干扰的,没有说都要使用同一个库的要求啊。
-
刚开始我也是这么认为的?后面仔细阅读官网我才发现,socket.io-client实际用的更多的不是websocket而是长轮询。在更多的时候会使用长轮询,为什么要使用长轮询?在浏览器不支持websocket的替代方案,兼容性更好,或者websocket异常断开了也会使用长轮询替代websocket。在这点socket.io确实做得很好。这就是为什么如果使用socket.io-client包在某些时候会有大量的http请求。sockiet.io要求前后端要使用他们自己开发的包还有一个原因是他们的websocket和长轮询有自己的规范,传参格式只有他们自己的包能理解然后通信。
-
这导致一个问题,就是前端用了他们的包,后端用了其他的包,或者不用包开启websocket都会疯狂报404!!!这也在官网有答案,怪我当时没仔细阅读官网(这里开启了翻译,看原文请前往官网查看英文版)。
-
这就是让我调了一天也连不上后端开启的websocket的原因!!!我前端使用了socket.io,但是后端没有使用他们的库去完成websocket的功能(后端是其他组的,所以他也不知道我们前端使用socket.io)。调试BUG差点让我怀疑人生,因为我们组内大多数系统都使用这个库,socket.io在npm上也有极高的下载量。这都说明了这个库的可靠性,但是我却没有发现他的使用限制。后面才发现我从一开始就错了。因为我也使用过原生websocket进行过通信,感觉挺简单的,自己封装一个也完全够用,没想到会在连接上后端websocket上花费这么多时间。而且socket.io不管是从命名还是用法上都有很高的迷惑性,让我们以为他内部使用更多的是websocket通信。
自己封装websocket
-
既然后端已经使用了其他包打开了websocket通信,让他换成socket.io的包再开发一次不太现实,而且长时间的BUG调试我也已经不想再使用这个socket.io包了。辣鸡!!!
-
那我就自己封装一个用呗,也不是太难。
- 第一步区别开发环境,这里是Vue框架,其他框架封装应该也差不多
// websocket.js function getUrl(){ // 开发环境加上端口 if(process.env.NODE_ENV ==== 'development') return 'ws://xx.com:1010/socket' else return 'ws://xx.com/socket' }
- 第二步封装WebSocket,这里只封装我项目用到的事件,这里放在对象里,可扩展性也是非常棒的,要加事件直接以同样的格式添加对应事件即可。如果不能使用class的,直接粗暴的定义一个对象放进去也可以。
// websocket.js class Socket{ constructor(){ this.socket = null } open(){ this.socket = new WebSocket(getUrl()) } message(callback = event => {}){ this.socket.onmessage = event => { callback(event) } } close(callback = event => {}){ this.socket.onclose= event => { callback(event) } } } export const socket = new Socket()
- 封装的websocket使用,如果是在vue的话,open和message建立websocket连接在created方法里面执行就可以了,然后在beforeDestory里面执行close关闭websocket连接即可。
import { socket } from './websocket.js' // 建立websocket连接 socket.open() function fetchTable(evnet){ ... } // 监听消息 socket.message(fetchTable) // 断开连接 socket.close()
总结
其实我一直都建议如果简单尽量自己封装去使用,可控性更高一点,自己也能学习更多一点。有人会说了,你这是重复造轮子。别人造轮子跟我有什么关系呢,我使用别人的库自己能学到的还是比较局限的,得要自己多造轮子。当自己造过轮子之后,觉得自己掌握了或者造的轮子没有别人那么好,这时候再造轮子才是重复造轮子。
万一一不小心自己造的轮子比别人好,那也能开源给其他用户使用了。为什么我之前使用原生websocket,却不自己封装,因为我想知道好的websocket库会带来怎样更好的体验,改善自己的封装的websocket结果因为自己没有仔细阅读官方文档,给自己埋了坑。 委屈.jpg