Web微信登录页面是https://wx.qq.com,以下内容以此页开始。
进入Web微信登录页面后,在开发者工具中查看网络请求情况,可以发现在二维码图片加载之前,浏览器发送了一次 GET 请求:
https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_=1532078129220
该请求用于获取登录uuid,分析发现有如下URL参数:
参数名 | 示例值 | 描述 |
---|---|---|
appid | wx782c26e4c19acffb | 这个值不变,表示来自Web版微信; |
redirect_uri | https%3A%2F%2Fwx2.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage | 跳转页面;非必须值; |
fun | new | 固定值; |
lang | zh_CN | 语言;zh_CN表示中文; |
_ | 1532078129220 | 13位时间戳; |
然后服务器返回数据:
window.QRLogin.code = 200; window.QRLogin.uuid = "wcXrINkB9Q==";
- window.QRLogin.code的值为200时表示成功,为其它值均表示失败。
- window.QRLogin.uuid的值为获取到的uuid,每次刷新会获取到不同的uuid,实际上uuid是服务端用来标识每一次登录的。
接着会发现如下 GET 请求:
https://login.weixin.qq.com/qrcode/wcXrINkB9Q==
该url为二维码图片的链接,url尾部的字符串即是上面获取到的uuid。
在获取二维码的请求之后,会发现如下 GET 请求:
https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=wcXrINkB9Q==&tip=0&r=1223005686&_=1532080293141
这是等待扫描登录并获取跳转url的请求。如果没有及时扫描二维码,一定时间后该请求会重复出现,表示浏览器在轮询请求。
URL参数分析:
数名 | 示例值 | 描述 |
---|---|---|
loginicon | true | 固定值; |
uid | wcXrINkB9Q== | 同前面的uuid; |
tip | 0或1 | 0表示等待用户扫码确认;1表示等待用户直接确认,用于push登陆时; |
r | 1223005686 | 10位随机数 |
_ | 1532080293141 | 13位时间戳; |
如果没有及时扫描二维码,服务器返回数据:
window.code=408;
- 表示没有轮询到认证信息,此时需要再次发送该请求。
如果一直没有扫描二维码,服务器返回数据:
window.code=400;
- 表示该次登录uuid失效,即二维码失效,此时会停止轮询,需要重新获取uuid才能继续。
及时扫码认证之后,在点击确认登录之前,服务器返回数据:
window.code=201;
- 表示微信APP端已经扫码,但还没有点击确认。
及时扫码并点击确认之后,服务器返回:
window.code=200;
window.redirect_uri="https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A51bGY49nxxxxxxx1wNPC3@qrticket_0&uuid=wcXrINkB9Q==&lang=zh_CN&scan=1532083897";
- window.code的值为200表示APP端认证成功。
- window.redirect_uri为需要跳转的url。
微信APP端认证后,会产生的新的 GET 请求:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A51bGY49nxxxxxxx1wNPC3@qrticket_0&uuid=wcXrINkB9Q==&lang=zh_CN&scan=1532083897&fun=new&version=v2
我们发现该请求即是上一步认证成功之后得到的redirect_uri再拼上&fun=new&version=v2。 该请求发送之后,其它web或pc端登录的微信会被踢下线。
URL参数分析:
数名 | 示例值 | 描述 |
---|---|---|
ticket | A51bGY49nxxxxxxx1wNPC3@qrticket_0 | 保存不变即可; |
uuid | wcXrINkB9Q== | 同前面的uuid; |
lang | zh_CN | 语言;zh_CN表示中文; |
scan | 1532083897 | 用户扫描的时间戳; |
fun | new | 固定值; |
version | v2 | 固定值; |
服务器返回数据:
<error>
<ret>0</ret>
<message></message>
<skey>@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp</skey>
<wxsid>8rwxxxxxxxxxHq2P</wxsid>
<wxuin>26xxx7</wxuin>
<pass_ticket>AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn=</pass_ticket>
<isgrayscale>1</isgrayscale>
</error>
(为了个人隐私,以上返回数据有打码)
- ret表示请求返回状态,0表示成功。
- skey、wxsid和wxuin都是具体微信用户的信息,不会变化,在后续的通讯中需要用到。
- pass_ticket在初始化页面时需要用到。
如果点击退出,我们会发现先后出现如下两个 POST 请求:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=0&skey=%40crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxlogout?redirect=1&type=1&skey=%40crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp
这两个请求唯一的区别就是type的值,先是0再是1。
URL参数分析:
数名 | 示例值 | 描述 |
---|---|---|
redirect | 1 | 固定值; |
type | 0或1 | 0或1,固定值; |
skey | %40crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp | 登录时获取的;需要urlencode。 |
FORM表单参数分析:
参数名 | 示例值 | 描述 |
---|---|---|
sid | 登录时获取的; | |
uin | 登录时获取的; |
服务器返回数据:
- 该请求会导致页面跳转,没有返回数据。
点击退出后,页面会出现点击直接登录的页面,点击登录之后,会发现产生一个叫webwxpushloginurl的 GET 请求:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxpushloginurl?uin=26xxx7
该请求是不扫码获取uuid的方式,仅用在手动退出登录之后,uuid获取之后还是继续1.3的等待确认。
URL参数分析:
数名 | 示例值 | 描述 |
---|---|---|
uin | 26xxx7 | 同前面获取的uin; |
服务器返回数据:
{
"ret": "0",
"msg": "all ok",
"uuid": "A_1_xxxw=="
}
- ret为0表示成功,为1表示uin错误等失败。
- uuid为新的uuid。经过反复“退出-push登录-退出-push登录”测试发现,全程uin保持不变,uuid会变化。
上面已经拿到了用户认证码,接着需要登录并初始化页面。
初始化页面就是向服务端请求常用的联系人等信息,如下 POST 请求:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=1219172280&lang=zh_CN&pass_ticket=AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn=
URL参数分析:
数名 | 示例值 | 描述 |
---|---|---|
r | 1219172280 | 10位随机数; |
lang | zh_CN | 语言;zh_CN表示中文; |
pass_ticket | AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn= | 上一步获取到的; |
POST的数据(JSON):
{
"BaseRequest": {
"DeviceID": "e659xxxxxxxx3006",
"Sid": "8rwxxxxxxxxxHq2P",
"Skey": "@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp",
"Uin": "26xxx7"
}
}
POST参数分析:
数名 | 示例值 | 描述 |
---|---|---|
BaseRequest.DeviceID | e659xxxxxxxx3006 | 设备ID,e拼上15位随机串; |
BaseRequest.Sid | rwxxxxxxxxxHq2P | 上一步获取到的wxsid; |
BaseRequest.Skey | crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp | 上一步获取到的skey; |
BaseRequest.Uin | 6xxx7 | 上一步获取到的wxuin; |
服务器返回数据:
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
"Count": 11,
"ContactList": [{
"Uin": 0,
"UserName": "filehelper",
"NickName": "...",
"HeadImgUrl": "...",
"ContactFlag": 5,
"MemberCount": 0,
"MemberList": [],
"RemarkName": "",
"HideInputBarFlag": 0,
"Sex": 0,
"Signature": "",
"VerifyFlag": 0,
"OwnerUin": 0,
"PYInitial": "WJCSZS",
"PYQuanPin": "wenjianchuanshuzhushou",
"RemarkPYInitial": "",
"RemarkPYQuanPin": "",
"StarFriend": 0,
"AppAccountFlag": 0,
"Statues": 0,
"AttrStatus": 0,
"Province": "",
"City": "",
"Alias": "",
"SnsFlag": 0,
"UniFriend": 0,
"DisplayName": "",
"ChatRoomId": 0,
"KeyWord": "fil",
"EncryChatRoomId": "",
"IsOwner": 0
}],
"SyncKey": {
"Count": 4,
"List": [{
"Key": 1,
"Val": 704152857
}, {
"Key": 2,
"Val": 704152894
}, {
"Key": 3,
"Val": 704152870
}, {
"Key": 1000,
"Val": 1532075042
}]
},
"User": {
...
},
"ChatSet": "...",
"SKey": "@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp",
"ClientVersion": 3697797,
"SystemTime": 1132000000,
"GrayScale": 1,
"InviteStartCount": 40,
"MPSubscribeMsgCount": 0,
"MPSubscribeMsgList": [],
"ClickReportInterval": 600000
}
- BaseResponse.Ret表示请求返回状态,0表示成功。
- ContactList为最近联系人列表。联系人的UserName以一个@开头为好友,两个@为群组。
- MPSubscribeMsg为公众号订阅消息。
- User是当前登录账户信息。
接着需要开启消息状态通知。我们可以看到如下 POST 请求:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket=AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn=
URL参数分析:
数名 | 示例值 | 描述 |
---|---|---|
lang | zh_CN | 语言;zh_CN表示中文; |
pass_ticket | AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn= | 同前面; |
POST的数据(JSON):
{
"BaseRequest": {
"DeviceID": "e81xxxxxxxxx7686",
"Sid": "8rwxxxxxxxxxHq2P",
"Skey": "@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp",
"Uin": "26xxx7"
},
"ClientMsgId": 1532xxxxx3374,
"Code": 3,
"FromUserName": "@56a0a9xxxxxxxxxxxxx54w0dxxxxbfab",
"ToUserName": "@56a0a9xxxxxxxxxxxxx54w0dxxxxbfab"
}
POST参数分析:
参数名 | 示例值 | 描述 |
---|---|---|
BaseRequestB | { "DeviceID":"e81xxxxxxxxx7686", "Sid":"8rwxxxxxxxxxHq2P", "Skey":"@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp", "Uin":"26xxx7" } |
每一次POST请求都会发送BaseRequest;其中DeviceID是字母e拼上15位随机字符串,其余三个都是前面获取到的认证信息。 |
ClientMsgId | 1532xxxxx3374 | 13位时间戳; |
Code | 3 | 固定值; |
FromUserName | @56a0a9xxxxxxxxxxxxx54w0dxxxxbfab | 页面加载时获取到的User.UserName; |
ToUserName | @56a0a9xxxxxxxxxxxxx54w0dxxxxbfab | 同FromUserName; |
服务器返回数据:
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
"MsgID": "2271xxxxxxxxxxxxx44"
}
- BaseResponse.Ret表示请求返回状态,0表示成功。
继续观察,我们没间隔一定的时间,浏览器会想服务器发送一个重复的 GET 请求:
https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=1532145313248&skey=%40crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp&sid=8rwxxxxxxxxxHq2P&uin=26xxx7&deviceid=e35077xxxx772148&synckey=1_704152857%7C2_704152996%7C3_704152955%7C1000_1532127722&_=1532145290777
该请求是轮询向服务器获取最新在线、消息等状态的。
URL参数分析:
数名 | 示例值 | 描述 |
---|---|---|
r | 1532145313248 | 13位时间戳; |
skey | %40crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp | 同前面;需要urlencode; |
sid | 8rwxxxxxxxxxHq2P | 同前面; |
uin | 26xxx7 同前面; | |
deviceid | e35077xxxx772148 | 设备ID,e拼上15位随机串; |
synckey | 1_704152857%7C2_704152996%7C3_704152955%7C1000_1532127722 | 由初始化登录页面信息返回串中Sync的list列表组成;需要urlencode; |
_ | 1532145290777 | 13位时间戳; |
服务器返回数据:
window.synccheck={retcode:"0",selector:"2"}
返回数据分析:
名称 | 示例值 | 描述 |
---|---|---|
retcode | 0 | 表示当前在线状态。 0:正常 1100:失败/登出微信 1101:从其它设备登录微信 |
selector | 2 | 表示消息状态。 0:正常 2:有新消息 4:目前发现修改了联系人备注会出现 7:手机操作了微信 |
接着可以看到获取全部联系人列表的 GET 请求:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket=AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn%253D&r=1532190636970&seq=0&skey=@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp
URL参数分析:
参数名 | 示例值 | 描述 |
---|---|---|
lang | zh_CN | 语言; |
pass_ticket | AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn%253D | 同前面获取到的; |
r | 1532190636970 | 13位时间戳; |
seq | 0 | 固定值; |
skey | @crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp | 同前面获取到的; |
服务器返回数据:
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
"MemberCount": 1,
"MemberList": [{
"Uin": 0,
"UserName": "weixin",
"NickName": "微信团队",
"HeadImgUrl": "/cgi-bin/mmwebwx-bin/webwxgeticon?seq=1&username=weixin&skey=@crypt_4fb399da_91a345e0be9deca5d61b183fc36a3a93",
"ContactFlag": 1,
"MemberCount": 0,
"MemberList": [],
"RemarkName": "",
"HideInputBarFlag": 0,
"Sex": 0,
"Signature": "微信团队官方帕啷",
"VerifyFlag": 56,
"OwnerUin": 0,
"PYInitial": "WXTD",
"PYQuanPin": "weixintuandui",
"RemarkPYInitial": "",
"RemarkPYQuanPin": "",
"StarFriend": 0,
"AppAccountFlag": 0,
"Statues": 0,
"AttrStatus": 4,
"Province": "",
"City": "",
"Alias": "",
"SnsFlag": 0,
"UniFriend": 0,
"DisplayName": "",
"ChatRoomId": 0,
"KeyWord": "wei",
"EncryChatRoomId": "",
"IsOwner": 0
}],
"Seq": 0
}
- BaseResponse.Ret为0表示请求成功。
- MemberCount表示联系人总数。
- MemberList表示联系人列表。这个列表中同时包含好友、群组、公众号。好友和公众号是通过ContactFlag来区分的,1是好友,2是群组,3是公众号。
- User内部字段介绍:
"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": ""
然后可以看到批量获取指定联系人信息的 POST 请求:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=1532246093335&lang=zh_CN&pass_ticket=AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn%253D
该请求用于批量获取好友信息,或者批量获取群聊中的成员信息。
URL参数分析:
参数名 | 示例值 | 描述 |
---|---|---|
type | ex | 不知道什么意思; |
r | 1532246093335 | 13位时间戳; |
lang | zh_CN | 语言; |
pass_ticket | AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn%253D | 前面获取到的; |
POST的数据(JSON):
{
"BaseRequest": {
"DeviceID": "e81xxxxxxxxx7686",
"Sid": "8rwxxxxxxxxxHq2P",
"Skey": "@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp",
"Uin": "26xxx7"
},
"Count": 2,
"List": [
{
"EncryChatRoomId": "",
"UserName": "@@76feaa87c63576aaxxxxxxxxeaaa7030c60a09d33"
},
{
"ChatRoomId": "",
"UserName": "@@55664b9ab69bbe5e6aaxxxxxxxxx778c17e11e9dab09c9a1"
}
]
}
POST参数分析:
参数名 | 示例值 | 描述 |
---|---|---|
BaseRequest | 基本请求参数,同前面; | |
Count | 要进行批量查询的用户数; | |
List | 批量指定要查询的UserName的列表;如果要获取好友信息,EncryChatRoomId或ChatRoomId为空,UserName为好友的UserName;如果要获取群聊成员的信息,EncryChatRoomId或ChatRoomId为群聊的UserName,UserName为成员的UserName。 |
服务器返回数据:
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
"Count": 2,
"ContactList": [{
"Uin": 0,
"UserName": "@@76feaa87c635763438059aaeaaa7030c60a09d33",
"NickName": "一啣ç<span class=\"emoji emoji1f525\"></span>¾¤)",
"HeadImgUrl": "/cgi-bin/mmwebwx-bin/webwxgetheadimg?seq=704138898&username=@@76feaa87c635763438059aaeaaa7030c60a09d33&skey=",
"ContactFlag": 3,
"MemberCount": 80,
"MemberList": [{
"Uin": 0,
"UserName": "@3a13860046f9f5cac66faba26f2bd0537f535",
"NickName": "龎",
"AttrStatus": 2147437,
"PYInitial": "",
"PYQuanPin": "",
"RemarkPYInitial": "",
"RemarkPYQuanPin": "",
"MemberStatus": 0,
"DisplayName": "",
"KeyWord": ""
}, ...],
"RemarkName": "",
"HideInputBarFlag": 0,
"Sex": 0,
"Signature": "",
"VerifyFlag": 0,
"OwnerUin": 0,
"PYInitial": "",
"PYQuanPin": "",
"RemarkPYInitial": "",
"RemarkPYQuanPin": "",
"StarFriend": 0,
"AppAccountFlag": 0,
"Statues": 0,
"AttrStatus": 0,
"Province": "",
"City": "",
"Alias": "",
"SnsFlag": 0,
"UniFriend": 0,
"DisplayName": "",
"ChatRoomId": 0,
"KeyWord": "",
"EncryChatRoomId": "@5fd8877457351e3a697",
"IsOwner": 0
}, {
"Uin": 0,
"UserName": "@f7dee38d1c3626c0e421c1f66deac0906559ac",
"NickName": "尕娅",
"HeadImgUrl": "/cgi-bin/mmwebwx-bin/webwxgeticon?seq=686458815&username=@f7dee38d1c3626c0e421c1f66deac0906559ac&skey=",
"ContactFlag": 259,
"MemberCount": 0,
"MemberList": [],
"RemarkName": "啢潧",
"HideInputBarFlag": 0,
"Sex": 2,
"Signature": "ä½ è<span class=\"emoji emoji1f48b\"></span>",
"VerifyFlag": 0,
"OwnerUin": 0,
"PYInitial": "XY",
"PYQuanPin": "",
"RemarkPYInitial": "",
"RemarkPYQuanPin": "",
"StarFriend": 0,
"AppAccountFlag": 0,
"Statues": 0,
"AttrStatus": 1047,
"Province": "å京",
"City": "",
"Alias": "",
"SnsFlag": 49,
"UniFriend": 0,
"DisplayName": "",
"ChatRoomId": 0,
"KeyWord": "",
"EncryChatRoomId": "0",
"IsOwner": 0
}]
}
- ContactList即是获取到的指定的联系人信息。
当我们修改联系人备注的时候,会发现浏览器发送了如下 POST 请求:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxoplog
POST的数据(JSON):
{
"BaseRequest": {
"DeviceID": "e81xxxxxxxxx7686",
"Sid": "8rwxxxxxxxxxHq2P",
"Skey": "@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp",
"Uin": "26xxx7"
},
"CmdId": 2,
"RemarkName": "新的备注名",
"UserName": "@07a2e8b4a1f98eb78a7xxxxxxxxxxxx5b7bc4908376xxx05917b"
}
POST参数分析:
参数名 | 示例值 | 描述 |
---|---|---|
BaseRequest | 基本请求参数,同其它; | |
CmdId | 2 | 固定值;有可能还有其它值来表示不同类型操作。 |
RemarkName | 新的备注名; | |
UserName | 要修改的联系人的UserName; |
服务器返回数据:
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
}
}
- BaseResponse.Ret表示操作成功。
我们发现2.4中的轮询请求每一次返回的数据中selector为2或者6时,都会发生如下的 POST 请求来从服务端获取新消息:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=8rwxxxxxxxxxHq2P&skey=@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp&pass_ticket=AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn%253D
URL参数分析:
参数名 | 示例值 | 描述 |
---|---|---|
sid | 8rwxxxxxxxxxHq2P | 同前面获取的; |
skey | @crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp | 同前面获取的; |
pass_ticket | AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn%253D | 同前面获取的; |
POST的数据(JSON):
{
"BaseRequest": {
"DeviceID": "e2089xxxxx902803",
"Sid": "8rwxxxxxxxxxHq2P",
"Skey": "@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp",
"Uin": 26xxx7
},
"SyncKey": {
"Count": 4,
"List": [{
"Key": 1,
"Val": 704153081
},
{
"Key": 2,
"Val": 704153167
},
{
"Key": 3,
"Val": 704153152
},
{
"Key": 1000,
"Val": 1532180042
}
]
},
"rr": 1112687259
}
POST参数分析:
参数名 | 示例值 | 描述 |
---|---|---|
BaseRequest | { "DeviceID": "e81xxxxxxxxx7686", "Sid": "8rwxxxxxxxxxHq2P", "Skey": "@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp", "Uin": "26xxx7" } |
每一次POST请求都会发送 BaseRequest;其中DeviceID是字母e拼上15位随机字符串,其余三个都是前面获取到的认证信息。 |
SyncKey | { "Count": ..., "List": [...] } |
前一次获取到的SyncKey;首次是初始化数据时获取的,zhiy之后都是通过本请求更新; |
服务端返回数据:
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
"AddMsgCount": 1,
"AddMsgList": [{
"MsgId": "462399962004142457",
"FromUserName": "@56a0a9xxxxxxxxxxxxx54w0dxxxxbfab",
"ToUserName": "@56a0a9xxxxxxxxxxxxx54w0dxxxxbfab",
"MsgType": 51,
"Content": "",
"Status": 3,
"ImgStatus": 1,
"CreateTime": 1532190642,
"VoiceLength": 0,
"PlayLength": 0,
"FileName": "",
"FileSize": "",
"MediaId": "",
"Url": "",
"AppMsgType": 0,
"StatusNotifyCode": 4,
"StatusNotifyUserName": "...",
"RecommendInfo": {
"UserName": "",
"NickName": "",
"QQNum": 0,
"Province": "",
"City": "",
"Content": "",
"Signature": "",
"Alias": "",
"Scene": 0,
"VerifyFlag": 0,
"AttrStatus": 0,
"Sex": 0,
"Ticket": "",
"OpCode": 0
},
"ForwardFlag": 0,
"AppInfo": {
"AppID": "",
"Type": 0
},
"HasProductId": 0,
"Ticket": "",
"ImgHeight": 0,
"ImgWidth": 0,
"SubMsgType": 0,
"NewMsgId": 462399962004142457,
"OriContent": "",
"EncryFileName": ""
}],
"ModContactCount": 0,
"ModContactList": [],
"DelContactCount": 0,
"DelContactList": [],
"ModChatRoomMemberCount": 0,
"ModChatRoomMemberList": [],
"Profile": {
"BitFlag": 0,
"UserName": {
"Buff": ""
},
"NickName": {
"Buff": ""
},
"BindUin": 0,
"BindEmail": {
"Buff": ""
},
"BindMobile": {
"Buff": ""
},
"Status": 0,
"Sex": 0,
"PersonalCard": 0,
"Alias": "",
"HeadImgUpdateFlag": 0,
"HeadImgUrl": "",
"Signature": ""
},
"ContinueFlag": 0,
"SyncKey": {
"Count": 7,
"List": [{
"Key": 1,
"Val": 704153081
}, {
"Key": 2,
"Val": 704153169
}, {
"Key": 3,
"Val": 704153152
}, {
"Key": 11,
"Val": 704152941
}, {
"Key": 201,
"Val": 1532190642
}, {
"Key": 1000,
"Val": 1532190561
}, {
"Key": 1001,
"Val": 1532180114
}]
},
"SKey": "",
"SyncCheckKey": {
"Count": 7,
"List": [{
"Key": 1,
"Val": 704153081
}, {
"Key": 2,
"Val": 704153169
}, {
"Key": 3,
"Val": 704153152
}, {
"Key": 11,
"Val": 704152941
}, {
"Key": 201,
"Val": 1532190642
}, {
"Key": 1000,
"Val": 1532190561
}, {
"Key": 1001,
"Val": 1532180114
}]
}
}
- AddMsgCount为新消息数目。
- AddMsgList为新消息列表。
- MsgType说明:
- 1:文本消息
- 3:图片消息
- 34:语音消息
- 37:VERIFYMSG(验证消息)
- 40:POSSIBLEFRIEND_MSG(可能的朋友的消息)
- 42:共享名片
- 43:视频通话消息
- 47:动画表情
- 48:位置消息
- 49:分享链接
- 50:VOIPMSG(VoIP消息)
- 51:微信初始化消息
- 52:VOIPNOTIFY(VoIP通知)
- 53:VOIPINVITE(VoIP邀请)
- 62:小视频
- 9999:SYSNOTICE(系统通知)
- 10000:系统消息
- 10002:撤回消息
- MsgType说明:
- SyncKey会暂存起来作为下一次请求的参数。
打开一个聊天界面,向好友发送一条消息,会发现产生如下 POST 请求:
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn%253D
URL参数分析:
参数名 | 示例值 | 描述 |
---|---|---|
pass_ticket | AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn%253D | 同前面获取的; |
POST的数据(JSON):
{
"BaseRequest": {
"DeviceID": "e57xxxxxxx94xx27",
"Sid": "8rwxxxxxxxxxHq2P",
"Skey": "@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp",
"Uin": "26xxx7"
},
"Msg": {
"ClientMsgId": "15321964202620841",
"Content": "这里是消息内容",
"FromUserName": "@da9d7631177b3c54492954010eb7",
"LocalID": "15321964202620841",
"ToUserName": "@d946a2006c12e85deda45c26b8cd42dbd3f03fa67be",
"Type": 1
},
"Scene": 0
}
POST参数分析:
Key | 示例值 | 描述 |
---|---|---|
BaseRequest | 同上; | |
Msg.ClientMsgId | 同LocalID; | |
Msg.Content | 消息内容;消息为媒体时,该值为媒体ID。 | |
Msg.FromUserName | 发送用户; | |
Msg.LocalID | 13位时间戳+4位随机数; | |
Msg.ToUserName | 接收用户; | |
Msg.Type | 1 | 消息类型;同3.1中接收的消息类型; |
Scene | 0 | 固定值; |
服务端返回数据:
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
"MsgID": "7650884298732299102",
"LocalID": "15321964202620841"
}
- LocalID是发送时指定的LocalID。
- MsgID是服务端的消息ID。
如果我们发送一个图片、文件等媒体类消息,会看到在发送消息请求前有如下 POST 请求:
https://file.wx.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json
若文件较小,则只会产生一个该请求,若文件较大,则会产生多个该请求。多个请求表示以分片的方式发送文件数据,分片大小约为524288。
FORM表单参数分析:
参数名 | 示例值 | 描述 |
---|---|---|
WU_FILE_0 | 页面文件组件ID;非必须; | |
bd00c8eed5c2cd522e69f38317b46903.jpg | 文件名;非必须; | |
image/jpeg | 文件的MimeType;非必须; | |
文件最后修改时间;非必须; | ||
99785 | 文件大小;非必须; | |
chunks | 3 | 文件分片数量;文件较大需要分片时必须; |
chunk | 0 | 文件分片序号;从0开始;文件较大需要分片时必须; |
mediatype | pic | 文件类型;图片为pic,视频为video,其它文件为doc;必须; |
uploadmediarequest | JSON字符串;必须; | |
webwx_data_ticket | cookie中的数据;必须; | |
pass_ticket | 登录时获取的;必须; | |
filename | 文件二进制数据;必须; |
uploadmediarequest结构示例:
{
"UploadType": 2,
"BaseRequest": {
"Uin": 1245,
"Sid": "zxaODbK4ed",
"Skey": "@crypt_4f399da_3c7a87e93b7872bce",
"DeviceID": "e69688819413"
},
"ClientMediaId": 153686311,
"TotalLen": 87508,
"StartPos": 0,
"DataLen": 87508,
"MediaType": 4,
"FromUserName": "@6feb88ee01067121479f686",
"ToUserName": "@6feb88ee0106f67121479f686",
"FileMd5": "717d1dbb9833c7cdbdd09ac"
}
服务端返回数据:
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
"MediaId": "@crypt_17ab5.................39bd9cfa9ab",
"StartPos": 99785,
"CDNThumbImgHeight": 56,
"CDNThumbImgWidth": 100,
"EncryFileName": "bd00c8e.....38317b46903.jpg"
}
上传成功后,返回数据中会有MediaId,如果是分片上传的,则最后一个请求会返回MediaId。
发送图片后,紧接着4.3的是如下POST请求:
https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsgimg?fun=async&f=json&lang=zh_CN&pass_ticket=xFAjPcq0eXh.......TYHHdHgVL52eHo%253D
URL参数分析:
数名 | 示例值 | 描述 |
---|---|---|
pass_ticket | xFAjPcq0eXh.......TYHHdHgVL52eHo%253D | 同前面获取的; |
POST的数据(JSON):
{
"BaseRequest": {
"Uin": 16...245,
"Sid": "KvCP..../TNqh8",
"Skey": "@crypt_4fb399da......9f1b3d997c4b5eef82",
"DeviceID": "e2825...3652448"
},
"Msg": {
"Type": 3,
"MediaId": "@crypt_17ab5.................39bd9cfa9ab",
"Content": "",
"FromUserName": "@3641f45.......69bed57642",
"ToUserName": "@3641f454....9bed57642",
"LocalID": "153691....0527",
"ClientMsgId": "1536....390527"
},
"Scene": 0
}
POST参数分析:
Key | 示例值 | 描述 |
---|---|---|
BaseRequest | 同上; | |
Msg.ClientMsgId | 同LocalID; | |
Msg.Content | 消息内容;消息为媒体时,该值为媒体ID。 | |
Msg.FromUserName | 发送用户; | |
Msg.LocalID | 13位时间戳+4位随机数; | |
Msg.ToUserName | 接收用户; | |
Msg.Type | 3 | 消息类型;同3.1中接收的消息类型; |
Msg.MediaId | 4.3接口中返回的MediaId; | |
Scene | 0 | 固定值; |
服务端返回数据:
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
},
"MsgID": "28832......8291836",
"LocalID": "1536.....54390527"
}
Web微信发送图片,需要先调4.3的接口将媒体文件上传到服务器,然后再调4.4的接口发送图片的相关信息。