这两天帮朋友的客户完善 IM 项目链上遗漏的 WEB 版本,所以就有了这篇文章,我把 git history
上的某节点做了删减,觉得以后可能用得到,也方便别人就给开源出来,本身没什么难度,可以当做演示或测试可行性使用。
这里面用的 app_key 与 app_secret 都是测试版的,就 100 个份额,没事的话,大家不要捣乱,谢谢。
源码
使用
clone
或下载源码包,打开后 cd 进入。
npm i
或 cnpm i
打开 http://localhost:8888 与 http://localhost:8888/test.html 测试 root 与 test 两名用户的聊天。
其他说明看 readme.md。
源码简单解读
原来项目是支持私聊与群聊等复杂功能的,这里只是单纯的单对单聊天,所以代码算是很精简了。
主要难点说下:
- server 获取 token 并返回给前端
- 前端监听相关状态与信息
首先是 server 端,对应文件是 server.js,有两个坑点:
向融云请求的 app_key 放在 headers 中,以及 post 内容格式为 formdata
问题 1 因为自己踩了,其实本质是不细心,希望大家不用再踩了。
问题 2 看代码即可:
请求关键参数的加密
const app_secret = '融云的 [app_key]'
const signAppKey = (nonce, timestamp) => {
let base = app_secret + nonce + timestamp
return enc.Hex.stringify(SHA1(base))
}
依赖为 npm 的 crypto-js 包,提供 enc 与 SHA1。
其他问题看源码即可,没什么太特殊的东西。
然后就是前端,主要还是官方文档的 cv 策略。
最大的坑就是命令的调用顺序:
- 初始化
- 监听
- 获取 token
- 连接
- 通信或拉取相关数据
恩,相信我,你会踩的。
连接状态监听,负责友好提示:
// 连接状态监听
RongIMClient.setConnectionStatusListener({
onChanged: (status) => {
// status 标识当前连接状态
switch(status) {
case RongIMLib.ConnectionStatus.CONNECTED:
console.log('链接成功')
break
case RongIMLib.ConnectionStatus.CONNECTING:
console.log('正在链接')
break
case RongIMLib.ConnectionStatus.DISCONNECTED:
console.log('断开连接')
break
case RongIMLib.ConnectionStatus.KICKED_OFFLINE_BY_OTHER_CLIENT:
console.log('其他设备登录, 本端被踢')
break
case RongIMLib.ConnectionStatus.DOMAIN_INCORRECT:
console.log('域名不正确, 请至开发者后台查看安全域名配置')
break
case RongIMLib.ConnectionStatus.NETWORK_UNAVAILABLE:
console.log('网络不可用, 此时可调用 reconnect 进行重连')
break
default:
console.log('链接状态为', status)
break
}
}
})
信息接收监听,负责页面逻辑:
// 收到消息监听
RongIMClient.setOnReceiveMessageListener({
// 接收到的消息
onReceived: res => {
let messageContent = res.content
// 判断消息类型
switch(res.messageType) {
case RongIMClient.MessageType.TextMessage: // 文字消息
console.log('文字内容', messageContent.content)
// res.senderUserId
console.log(res)
this.reciveMessage(res)
break
case RongIMClient.MessageType.ImageMessage: // 图片消息
console.log('图片缩略图 base64', messageContent.content)
console.log('原图 url', messageContent.imageUri)
break
case RongIMClient.MessageType.HQVoiceMessage: // 音频消息
console.log('音频 type ', messageContent.type) // 编解码类型,默认为 aac 音频
console.log('音频 url', messageContent.remoteUrl) // 播放:<audio src={remoteUrl} />
console.log('音频 时长', messageContent.duration)
break
case RongIMClient.MessageType.RichContentMessage: // 富文本(图文)消息
console.log('文本内容', messageContent.content)
console.log('图片 base64', messageContent.imageUri)
console.log('原图 url', messageContent.url)
break
case RongIMClient.MessageType.UnknownMessage: // 未知消息
console.log('未知消息, 请检查消息自定义格式是否正确', message)
break
default:
console.log('收到消息', res)
this.reciveMessage(res)
break
}
}
})
然后就是连接了:
// 融云连接
RongIMClient.connect(token, {
onSuccess: (userId) => {
console.log('连接成功, 用户 id 为', userId)
},
onTokenIncorrect: () => {
console.log('连接失败, 失败原因: token 无效')
},
onError: (errorCode) => {
let info = ''
switch(errorCode) {
case RongIMLib.ErrorCode.TIMEOUT:
info = '链接超时'
break
case RongIMLib.ConnectionState.UNACCEPTABLE_PAROTOCOL_VERSION:
info = '不可接受的协议版本'
break
case RongIMLib.ConnectionState.IDENTIFIER_REJECTED:
info = 'appkey 不正确'
break
case RongIMLib.ConnectionState.SERVER_UNAVAILABLE:
info = '服务器不可用'
break
default:
info = errorCode
break
}
console.log('连接失败, 失败原因: ', info)
}
})
注意 userId 是唯一的并且入融云项目库的,name 与 portraitUri 是必填任意内容的。这几个东西应该从你的数据库中取出的用户对照信息,userId 必然是唯一的。
其他代码就是常规的页面渲染等等了,不再赘述。
注意
前端代码 JS 部分为了方便改写用的是 ES6,IE 与 Safari 并不适用。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。