IM平滑迁移方案

网易云信多年来的稳定IM即时通讯服务,在开发者中积累了良好的口碑。部分开发者希望接入云信的IM服务,但正在使用自研或友商提供的即时通讯服务。针对这一场景,网易云信为客户贴身打造了一套迁移方案,并且成功为多家客户实现了平滑迁移。

基本概念

前期准备

进行IM平滑迁移,需要提前进行以下准备:

迁移方式

强制升级迁移

强制升级迁移的方式,是指在完成云信IM接入后,新应用上架,强制所有的老应用升级至新应用的迁移方式。此方式下不存在新老应用的兼容问题。

新老兼容迁移

新老兼容迁移的方式,是指在迁移过程中,云信IM服务器和原IM服务器同时提供服务,新应用和旧应用并存,支持新旧应用互通。待用户逐步更新至新应用,旧应用逐步无人使用后,原IM服务器停止服务。

新老兼容迁移过程中,会涉及到新老应用的增量消息发送的保障。因此需要原IM服务器可以提供消息抄送和服务端发送消息的功能。一条消息由老应用的用户发送到新应用的用户,需要经历以下几个步骤:

  1. 老应用用户发送消息至原IM服务器
  2. 原IM服务器提供消息抄送功能,将消息抄送给应用服务器
  3. 应用服务器收到消息抄送后,调用云信提供的服务端消息发送API发送消息
  4. 云信服务器将消息发送给新应用的指定用户

反之,一条消息由新应用发送到老应用,也通过类似的4个步骤实现。

优势对比

不同的迁移方式适应不同的场景,各有优劣,需要依赖的条件也不同。详情如下:

迁移流程

迁移步骤

注:以下接口调用时,请将调用频次控制在1秒100次以下。以免触发频控导致调用失败。

1、用户资料迁移

使用注册账号完成对应用户账号的注册与用户资料迁移。后续也可以通过设置用户资料完成用户资料的二次修改。

注:请先完成用户迁移,再进行后续操作。请在自身业务服务器上维护记录好所有用户的accid。

2、用户关系迁移

根据云信官网提供的用户关系托管接口完成好友、黑名单等关系的迁移。

3、群组迁移

根据云信官网提供的群组功能相关接口完成群组的迁移。

注:请在自身业务服务器上维护记录好所有群组tid。

4、历史消息迁移

若图片、语音等消息里的文件也要迁移并存储到云信服务器,需先使用文件上传接口完成上传来拿到云信返回的 url,然后替换原消息体中的 url。

4.1 历史存量消息(迁移前已产生)

历史存量消息,一般为某个约定时刻之前(约定时刻之后的参见下文增量消息)的历史消息,请按照要求提供以下信息:

另外:针对群消息,若新进群用户希望能查阅历史消息,请在云信控制台打开「新进群用户获取历史消息开关」,配置方法:应用 > IM专业版/IM免费版 > 功能配置 > 新进群用户获取历史消息配置 > 新进群用户获取历史消息开关(默认关闭)。

4.2 增量消息

若应用迁移模式是新老兼容迁移,则在迁移过程中,会产生增量消息,考虑到历史消息迁移存在实时性的问题,可使用如下方式:

存量消息与增量消息迁移之后,可通过客户端 SDK 和服务端 API 的 查询云端历史消息接口 拉取验证。

注:免费版应用可查最近30天内的消息,正式版应用默认可查一年内的消息。

5、最近联系人列表迁移

最近联系人列表(最近会话列表)的迁移,通过接收云端主动下推的离线消息与漫游消息,自动触发产生最近会话列表。

由于离线和漫游消息有限,可通过如下方法维护更多最近会话列表:

消息体格式介绍

注1:不能同时存在两条消息的 msgid 、 from 、 to/tid 、 createTime 这四者相同,否则会被覆盖。

注2:ext字段为消息扩展字段,若原先无该字段,可忽略。

注3:createTime请使用毫秒级别。

单聊消息

aaa 发给 bbb 一条文本消息

{"data":{"ext":"ext..","clientType":"2","createTime":1513685265481,"msgid":1,"from":"aaa","to":"bbb","body":"测试"},"type":0}

aaa 发给 bbb 一条图片消息

{"data":{"ext":"ext..","clientType":"2","createTime":1513685265528,"msgid":11,"from":"aaa","to":"bbb","attach":"{\"h\":780,\"ext\":\"jpg\
“,\"size\":2589,\"w\":1040,\"name\":\"haha\",\"url\":\"https://a1.ease5fb40/2c93186d\"}"},"type":1}

aaa 发给 bbb 一条语音消息(dur 单位是 ms)

{"data":{"ext":"ext..","clientType":"2","createTime":1513685265528,"msgid":101,"from":"aaa","to":"bbb","attach":"{\"size\":5232,\"ext\":\" amr\",\"dur\":8000,\"url\":\"https://a1.easemob.files/f3bdaffe174cee99f\"}"},"type":2}

aaa 发给 bbb 一条视频消息(dur 单位是 ms)

{"data":{"ext":"ext..","clientType":"2","createTime":1513685265528,"msgid":1001,"from":"aaa","to":"bbb","attach":"{\"h\":780,\"w\":1040,\"size\":5232,\"ext\":\" mp4\",\"dur\":8000,\"url\":\"https://a1.easeatfiles/f3-ffe174cee99f\"}"},"type":3}

aaa 发给 bbb 一条地理位置消息

{"data":{"attach":"{\"lng\":\"116.655294\",\"title\":\"新华南路 145 号
\",\"lat\":\"39.89611\"}","clientType":"1","createTime":"1537262375000","ext":"","msgid":100561,"from":"aaa","to":"bbb"},"type":"4"}

aaa 发给 bbb 一条文件消息

{"data":{"ext":"ext..","clientType":"2","createTime":1513685265528,"msgid":10501,"from":"aaa","to":"bbb","attach":"{\"size\":5232,\"ext\":\" ttf\",\"url\":\"https://a1.easemob.com/hywtfiles/f3bda-ffe174cee99f\"}"},"type":6}

aaa 发给 bbb 一条自定义消息

{"data": {"attach": {"param": {"ptId": "f5","pe": "http: //img.u.com/zmw/upad/2014/92!/0/quty-90/fobp","artisanName": "","productPrice": "66.0","productName":
"helase"},"type": "1","url": "","desc": "作息"},"clientType": "1","createTime": "1539499209000","ext": "","msgid":10534501,"from": "aaa","to": "bbb"},"type": "100"}

群聊消息

A 发了一条文本消息

{"data":{"ext":"ext..","createTime":1511513944827,"clientType":16,"msgid":1,"accid":"aaa","body":"哈哈","tid":1},"type":0}

A 发了一条图片消息

{"data":{"ext":"ext..","createTime":1511513944827,"clientType":16,"msgid":1231,"accid":"aaa","attach":"{\"h\":780,\"ext\":\"jpg\",\"size\":257389,\"w\":1040,\"name\":\"haha\",\"url\":\"https://a1.easemob.com/hywwjugh/jugh/chatfiles/ba05f0e0- e469-11e7-86e2- 5b402c93186d\"}","tid":1},"type":1}

A 发了一条语音消息(dur 的单位是 ms)

{"data":{"ext":"ext..","createTime":1511513944827,"clientType":16,"msgid":13,"accid":"aaa","attach":"{\"size\":5232,\"ext\":\" amr\",\"dur\":8000,\"url\":\"https://a1.easemob.com/hywwjugh/jugh/chatfiles/f3bda300-e469-11e7-9508-ffe174ce e99f\"}","tid":1},"type":2}

其他类型消息参考单聊

三、群操作通知消息

B 被 A 拉进群

{"data":{"accid2":"aaa","createTime":1511513944871,"clientType":16,"msgid":3,"accid":"bbb","tid":1},"type":101}

A 把 B 踢出群

{"data":{"accid2":"bbb","createTime":1511513944871,"clientType":16,"msgid":4,"accid":"aaa","tid":1},"type":102}

A 禁言 C

{"data":{"accid2":"ccc","createTime":1511513944871,"clientType":16,"msgid":5,"accid":"aaa","tid":1},"type":103}

A 取消禁言 C

{"data":{"accid2":"ccc","createTime":1511513944871,"clientType":16,"msgid":6,"accid":"aaa","tid":1},"type":104}

A 任命 C 为管理员

{"data":{"accid2":"ccc","createTime":1511513944871,"clientType":16,"msgid":7,"accid":"aaa","tid":1},"type":105}

A 取消 C 为管理员

{"data":{"accid2":"ccc","createTime":1511513944871,"clientType":16,"msgid":8,"accid":"aaa","tid":1},"type":106}

A 修改群信息(修改了群介绍)

{"data":{"createTime":1511513944871,"clientType":16,"tinfo":{"14":"new","tid":1},"msgid":9,"accid":"aaa","tid":1},"type":107}

A 修改群信息(修改了加群认证方式)

{"data":{"createTime":1511513944872,"clientType":16,"tinfo":{"16":"0","tid":1},"msgid":10,"accid":"aaa","tid":1},"type":107}

A 把群转让给了 C

{"data":{"accid2":"ccc","createTime":1511513944872,"clientType":16,"msgid":11,"accid":"aaa","tid":1},"type":108}

A 退出了群

{"data":{"createTime":1511513944872,"clientType":16,"msgid":12,"accid":"aaa","tid":1},"type":109}

C 解散了群

{"data":{"createTime":1511513944872,"clientType":16,"msgid":13,"accid":"ccc","tid":1},"type":110}

群相关参数介绍:

对于修改群信息这类通知:

tinfo这个子json串,必须包含 tid,且和父串中的 tid 保持一致。例子中可以看到,14这个key表示的是群介绍,16这个key 表示的是加群方式,其他项如下:

key 数据类型 含义
14 string 表示群介绍
15 string 表示群公告
16 int 表示入群权限,0 表示不需要申请,1 表示需要申请,2 表示不允许申请
17 int 表示群状态,0 表示正常状态,1 表示禁言
18 string 表示第三方扩展字段
19 string 表示第三方服务器扩展字段
20 string 群 icon
21 int 表示被邀请人同意方式,0 表示需要同意,1 表示不需要同意
22 int 表示谁可以邀请他人入群,0 表示管理员,1 表示所有人
23 int 表示谁可以修改群资料,0 表示管理员,1 表示所有人
24 int 表示谁可以更新群自定义属性,0 表示管理员,1 表示所有人

客户端类型参数介绍:

对于客户端类型(ClientType),表示上述操作的来源客户端:

枚举值 客户端类型
1 表示 AOS(Android)
2 表示 iOS
4 表示 PC
8 表示 WINPHONE
16 表示 WEB
32 表示 REST(Server)
64 表示 MAC