《PHP开发微信聊天机器人之WEB版微信协议部分功能分析》要点:
本文介绍了PHP开发微信聊天机器人之WEB版微信协议部分功能分析,希望对您有用。如果有疑问,可以联系我们。
相关主题:web微信和微信机器人
2016-09-20更新,以下按一个微信WEB登录的全过程依次分析接口:
首先,我们打开浏览器端发起登陆请求,系统返回一个唯一的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 = "xxxxxxXxx=="
如下:
得到uuid之后,请求二维码: https://login.weixin.qq.com/qrcode/wYGuImiikg==
返回的数据:
一张二维码图片
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";12
PS:scan值为时间戳(s),js中的实现为Date.now()
登录成功之前,每隔27s左右就会重新确认状态,如下:
请求: 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>1
解析可以得到:skey
、sid
、uin
、pass_ticket
的值。
请求:
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) },123
返回数据(JSON):
部分分析:
本次ContactList里只有10个好友or群组,应该是最近的10个活跃对象(个数不是固定的);
另外,可以通过UserName来区分好友or群组,一个”@”为好友,两个”@”为群组。
MPSubscribeMsg为公众号推送的阅读文章
User其实就是自己账号信息(用在顶部的头像)
请求:
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" }12345678
请求:
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": "<span class=\"emoji emoji270a\"></span>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": ""123456789101112131415161718192021222324252627282930
请求:
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: 里面有群组的名称、群组成员等信息
url | https://webpush2.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"}1
其中各个返回值的含义如下:
retcode: 0 正常 1100 失败/退出微信 selector: 0 正常 2 新的消息 7 进入/离开聊天界面1234567
请求:
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):
请求:
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相同123456
返回的数据(JSON):
{ "BaseResponse": { "Ret": 0, "ErrMsg": "" } , "MsgID": "5897491620102102783", "LocalID": "14672043702850802" }123456789
以上这些就可以用代码实现交互过程啦。