IT技术互动交流平台

WEB版微信协议部分功能分析

发布日期:2016-09-22 20:34:02

更新

不知道是不是因为网页版微信的console.log问题被发现(可以看看知乎这里),中秋假期里出了新版本,有一些地方改了。但具体哪里改了还没时间去深究,不过可以发现同步更新的时间间隔改成了25s,如下图:
同步间隔25s

可以对比原来的27s间隔(点我)

有发现其他改变的地方的朋友有兴趣的话可以提出来,大家一起交流。

 

2016-09-20更新


因为项目需要,对网页版微信的通信过程做了一番研究。以下是探索过程中的分析笔记。
 

登录

1. 获取UUID

首先,我们打开浏览器端发起登陆请求,系统返回一个唯一的uid,并将uid的信息绘制成二维码返回给用户。
这里写图片描述

请求:

url https://login.wx.qq.com/jslogin
method GET
Params appid:wx782c26e4c19acffb,应用ID(固定值)
redirect_uri:https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage
fun : new
lang : en_US 或 zh_CN,浏览器的语言
_ : 1466394395577,时间戳(ms,js中的实现为new Date)

%2F是’/ ‘的URL编码

返回数据(String):
window.QRLogin.code = 200; window.QRLogin.uuid = 'xxx'
如下:
这里写图片描述
 

2. 显示二维码

得到uuid之后,请求二维码:
https://login.weixin.qq.com/qrcode/wYGuImiikg==

返回的数据:
一张二维码图片
 

3. 等待扫码登录

url https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login
method GET
params loginicon : true
uuid : 获取到的uuid
tip : 1-未扫描 0-已扫描
r : 1698811404(时间戳取反,js中的实现:~new Date)
_ : 时间戳


返回数据(String):

window.code=xxx;

xxx值可以是:
    408 登陆超时
    201 扫描成功
    200 确认登录

如下:
(1)如果一直没有扫描,则得到408返回码
这里写图片描述

(2)扫描成功后,得到201返回码:
这里写图片描述

扫描成功后网页上会出现你的账号头像,userAvatar后面的字符串是将要登录账号的头像(直接将userAvatar后面的字符串放入地址栏就可以得到你的头像)

(3)登录成功,得到200返回码:
这里写图片描述

登录成功后的返回数据(String):

window.code=200;
window.redirect_uri='https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=AXMhC-q8hFm1YagQCIfejW0W@qrticket_0&uuid=wYGRJ91k7A==&lang=en_US&scan=1466408041';

PS:scan值为时间戳(s),js中的实现为Date.now()


登录成功之前,每隔27s左右就会重新确认状态,如下:
这里写图片描述
 

4. 获取登录参数(uin、skey、sid、pass_ticket)

请求:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=ATB6rg04PsHA1mpklaCZd2Tu@qrticket_0&uuid=AaGxsJd1kQ==&lang=zh_CN&scan=1467183053&fun=new&version=v2
PS:其实这个请求是在window.redirect_uri最后拼接”&fun=new&version=v2”

url https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage
method GET
params ticket:xxx
uuid:xxx
lang:xxx
scan:扫码成功后返回的时间戳(s)
fun:new
version:v2


返回数据(XML):

<error><ret>0</ret><message>OK</message><skey>xxx</skey><wxsid>xxx</wxsid><wxuin>xxx</wxuin><pass_ticket>xxx</pass_ticket><isgrayscale>1</isgrayscale></error>

解析可以得到:skey、sid、uin、pass_ticket的值。


 

微信初始化

1. 获取初始化信息(账号头像信息、聊天好友、阅读等)

请求:

url https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=xxx&pass_ticket=xxx
method POST
params BaseRequest:
{
DeviceID:”xxx”,
Sid: “xxx”,
Skey: “xxx”,
Uin: “xxx”,
}

PS:DeviceID值的由来:e+15位随机数,JS中的实现如下:

getDeviceID: function() {
    return 'e' + ('' + Math.random().toFixed(15)).substring(2, 17)
},


返回数据(JSON):
这里写图片描述
部分分析:
本次ContactList里只有10个好友or群组,应该是最近的10个活跃对象(个数不是固定的);
另外,可以通过UserName来区分好友or群组,一个”@”为好友,两个”@”为群组。
MPSubscribeMsg为公众号推送的阅读文章
User其实就是自己账号信息(用在顶部的头像)
 

2. 开启微信状态通知

请求:

url https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket=xxx
method POST
data JSON
params BaseRequest:
{
ClientMsgId:时间戳(ms)
Code:3
FromUserName:”自己的ID”
ToUserName:”自己的ID”
}


返回的数据(JSON):

{
'BaseResponse': {
'Ret': 0,
'ErrMsg': ''
}
,
'MsgID': '8219790123546360012'
}

 

3. 获取好友列表(webwxgetcontact)

请求:

url https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact
method GET
params lang=zh_CN
pass_ticket=xxx
r=xxx
seq=0
skey=xxx


返回数据(JSON):
这里写图片描述
PS:
这个列表中包含好友、群组、公众号。
好友和公众号是通过”ContactFlag”区分的,值为1是好友,值为3是公众号。

关于NickName,可以带表情之类,所以有的人昵称是这样的:
'NickName': 'Wade'

部分字段说明:

'Uin': 0,
'UserName': 用户名称,一个'@'为好友,两个'@'为群组
'NickName': 昵称
'HeadImgUrl':头像图片链接地址
'ContactFlag': 1-好友, 2-群组, 3-公众号
'MemberCount': 成员数量,只有在群组信息中才有效,
'MemberList': 成员列表,
'RemarkName': 备注名称
'HideInputBarFlag': 0,
'Sex': 性别,0-未设置(公众号、保密),1-男,2-女
'Signature': 公众号的功能介绍 or 好友的个性签名
'VerifyFlag': 0,
'OwnerUin': 0,
'PYInitial': 用户名拼音缩写
'PYQuanPin': 用户名拼音全拼
'RemarkPYInitial':备注拼音缩写
'RemarkPYQuanPin': 备注拼音全拼
'StarFriend': 是否为星标朋友  0-否  1-是
'AppAccountFlag': 0,
'Statues': 0,
'AttrStatus': 119911,
'Province': 省
'City': 市
'Alias': 
'SnsFlag': 17,
'UniFriend': 0,
'DisplayName': '',
'ChatRoomId': 0,
'KeyWord': 
'EncryChatRoomId': ''

 

4. 请求群组列表(webwxbatchgetcontact)

请求:

url https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=xxx&lang=zh_CN&pass_ticket=xxx
method POST
params BaseRequest:
{
DeviceID:”xxx”
Sid:”xxx”
Skey:”xxx”
Uin:xxx
}
Count:4
List:
[
0:{UserName: “xxx”, EncryChatRoomId: “”}
1:{UserName: “xxx”, ChatRoomId: “”}

]

Q:EncryChatRoomId与ChatRoomId有什么区别?

(1) 第一次请求得到最近一段时间内活跃的群组(但不知道腾讯是怎么定义这段时间的):
POST表单提交的内容:
这里写图片描述

上面LIST的内容是从微信初始化时(webwxinit)返回的数据中得到的:
这里写图片描述

返回到结果如下:
这里写图片描述
里面有群组的名称、群组成员等信息

(2) 第二次请求得到剩下的(最近没有交流的)群组:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=xxx&lang=zh_CN&pass_ticket=xxx

POST表单提交的内容:
这里写图片描述
PS:应该都是在获取好友列表(webwxgetcontact)的返回数据中提取出来的(通过判断”@@”即可)

返回到结果如下:
这里写图片描述
PS: 里面有群组的名称、群组成员等信息

 

消息更新

1.消息检查(syncCheck)

url https://webpush4.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck
method GET
params r=时间戳(ms)
skey=xxx
sid=xxx
uin=xxx
deviceid=xxx
synckey=1_654585659%7C2_654585745%7C3_654585673%7C1000_1467162721
_=1467184052133

PS:%7C是’| ‘的URL编码

返回数据(String):

window.synccheck={retcode:'xxx',selector:'xxx'}

其中各个返回值的含义如下:

retcode:
    0 正常
    1100 失败/退出微信
selector:
    0 正常
    2 新的消息
    7 进入/离开聊天界面

 

2. 获取最新消息(webwxsync)

请求:

url https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=xxx&skey=xxx&lang=zh_CN&pass_ticket=xxx
method POST
params BaseRequest:
{
DeviceID:”xxx”
Sid:”xxx”
Skey:”xxx”
Uin:xxx
}
SyncKey:
{
Count: 8
List:
[
0:{Key: 1, Val: 654585659}

7:{Key: 1001, Val: 1467198392}
]
}
rr:1678170712


rr: 时间戳取反
SyscKey值:
第一次更新时POST提交的SyncKey部分是从前面webwxinit请求的返回信息中得到的,如下图;
之后的每次更新都会使用最新的SyncKey进行请求。
这里写图片描述

返回的数据(JSON):
这里写图片描述

 

发送消息

发送消息(webwxsendmsg)

请求:

url https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket=xxx
method POST
params BaseRequest:
{
DeviceID:”xxx”
Sid:”xxx”
Skey:”xxx”
Uin:xxx
}
Msg:
{
ClientMsgId:”14672041846800613”
Content:”hello, myself.”
FromUserName:”xxx”
LocalID:”14672041846800613”
ToUserName:”filehelper”
Type:1
}
Scene:0

可以看到我往<文件传输助手>发送了”hello,myself”

字段说明:

Type: 1 文字消息,3 图片消息(先把图片上传得到MediaId再调用webwxsendmsg发送),其他消息类型没试。
Content: 要发送的消息(发送图片消息时该字段为MediaId)
FromUserName: 自己的ID
ToUserName: 好友的ID
ClientMsgId: 时间戳左移4位随后补上4位随机数 
LocalID: 与clientMsgId相同

返回的数据(JSON):

{
'BaseResponse': {
'Ret': 0,
'ErrMsg': ''
}
,
'MsgID': '5897491620102102783',
'LocalID': '14672043702850802'
}


 


分析完这些就可以用代码实现交互过程啦。


笔记中有些内容的展示参考了一些前人的表达方式。而且像很多人直接套用了Bootstrap框架导致千篇一律一样,Markdown简洁的标记语法也让很多文章的格式上相似。但这正是Markdown出现的目的之一吧,简洁、统一。

Tag标签: 部分   功能  
  • 专题推荐

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规