问题描述:最近有项目涉及到前后端websocket通信,在封装好了websocket相关的方法后,需要在onmessage里面拿到后端的返回信息。也看了网上很多实例,大部分都是直接在.vue文件里面去初始化websocket,考虑到自己项目的实际情况决定将websocket的一些方法抽离出来,方便复用。这里记录一下onmessage事件的处理
import { websocketConfig } from '../config'
let ws = null;
let heartBeatTimer = null;
/** 建立websocket连接*/
const handleCreateWS = () => {
//...省略一些代码
ws.onmessage = websocketOnmessage
//...省略一些代码
}
//...省略一些代码
/** 数据接收处理*/
const websocketOnmessage = (e) => {
let customEvent = new CustomEvent('onmessageWS', {
detail: {
data: e.data
},
bubbles: false, //该事件是否冒泡
cancelable: false, //该事件能否被取消
composed: false //指示事件是否会在影子DOM根节点之外触发侦听器。
})
if (window.dispatchEvent) {
window.dispatchEvent(customEvent);
} else {
window.fireEvent(customEvent);
}
}
export default {handleCreateWS //...省略一些希望暴露出去的api方法 }
上面的代码是封装的方法,因为将websocket逻辑部分做了抽离,所以处理事件接收就需要动一动脑筋。开始是打算直接在websocketOnmessage方法中通过区分data的信息去调用不同的事件。后来考虑到消息的多样性,后期肯定会有代码臃肿难维护的问题。所以为了将不同的消息放在各自的组件中处理,最终考虑使用自定义事件的方法,将事件挂载到window上,在页面中使用只需要监听事件,拿到对应的数据再经行处理就ok了
<template>
<div>组件</div>
</template>
<script>
import scoket from '@/utils/websocket'
export default {
created() {
scoket.handleCreateWS()
},
mounted() {
window.addEventListener('onmessageWS', this.handleMessage() })
},
destroyed() {
window.removeEventListener('onmessageWS'})
},
methods: {
handleMessage(e) {
console.log('监听到了')
console.log('---------------')
console.log(e)
console.log('---------------')
}
}
}
</script>
<style lang="less" scoped>
</style>
依照以往监听滚动,监听resize的经验,写到这里,一切都感觉很OK。兴奋的跑一跑代码,问题出现了。页面中拿不到onmessage的消息,打印结果是undefined。找了好久的问题,也查看了很多的文章,几乎没有找到相关的问题。难受!
经过不懈努力,终于找到了问题所在,问题出在this指向。
mounted() {
//报错的写法,这里的this指向的是window
window.addEventListener('onmessageWS', this.handleMessage(), false)
//修改之后的写法,用箭头函数承接一下,this指向vue实例
window.addEventListener('onmessageWS', (e) => { this.handleMessage(e), false })
},
不知道是不是vue对监听其他的浏览器事件进行过处理。在本次实践中自定义事件使用常规的写法不能直接使用this来使用methods里面的方法。这也是因为自己的常规思维导致的错误。记录一下,希望以后能避免采坑。
---------------------------------------------补充问题------------------------------------------------
如何在websocket里面传递参数?后台为了保证连接的安全性,要求在连接websocket的时候加入token,比较可靠的解决方法目前有两种:
- websocket请求头中可以包含Sec-WebSocket-Protocol这个属性,该属性是一个自定义的子协议。它从客户端发送到服务器并返回从服务器到客户端确认子协议。我们可以利用这个属性添加token。这种实现方式需要后端处理一下他们的代码!
- 直接在请求接口里面添加token参数
let { wsUri, token = '12345678' } = websocketConfig;
ws = new WebSocket(wsUri, token);
let { wsUri } = websocketConfig;
new WebSocket(`${wsUri }?token='xxxxx'`)