diff --git a/doc/web-weixin-api.md b/doc/web-weixin-api.md new file mode 100644 index 0000000..401def4 --- /dev/null +++ b/doc/web-weixin-api.md @@ -0,0 +1,993 @@ +# Web微信API文档 + +## 1、登录 + +Web微信登录页面是[https://wx.qq.com](https://wx.qq.com),以下内容以此页开始。 + +### 1.1、获取登录uuid + +进入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是服务端用来标识每一次登录的。 + +### 1.2、获取二维码 + +接着会发现如下 GET 请求: + +``` +https://login.weixin.qq.com/qrcode/wcXrINkB9Q== +``` + +该url为二维码图片的链接,url尾部的字符串即是上面获取到的uuid。 + +### 1.3、等待确认登录 + +在获取二维码的请求之后,会发现如下 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。 + +### 1.4、获取登录认证码 + +微信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|固定值;| + +服务器返回数据: + +```XML + +    0 +     +    @crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp +    8rwxxxxxxxxxHq2P +    26xxx7 +    AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn= +    1 + +``` + +***(为了个人隐私,以上返回数据有打码)*** + +- ret表示请求返回状态,0表示成功。 +- skey、wxsid和wxuin都是具体微信用户的信息,不会变化,在后续的通讯中需要用到。 +- pass_ticket在初始化页面时需要用到。 + +### 1.5、退出登录 + +如果点击退出,我们会发现先后出现如下两个 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||登录时获取的;| + +服务器返回数据: + +- 该请求会导致页面跳转,没有返回数据。 + +### 1.6、push登录 + +点击退出后,页面会出现点击直接登录的页面,点击登录之后,会发现产生一个叫webwxpushloginurl的 GET 请求: + +``` +https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxpushloginurl?uin=26xxx7 +``` + +该请求是不扫码获取uuid的方式,仅用在手动退出登录之后,uuid获取之后还是继续1.3的等待确认。 + +URL参数分析: + +|数名|示例值|描述| +|uin|26xxx7|同前面获取的uin;| + +服务器返回数据: + +```JavaScript +{ + "ret": "0", + "msg": "all ok", + "uuid": "A_1_xxxw==" +} +``` + +- ret为0表示成功,为1表示uin错误等失败。 +- uuid为新的uuid。经过反复“退出-push登录-退出-push登录”测试发现,全程uin保持不变,uuid会变化。 + +## 2、数据同步 + +### 2.1、页面初始化 + +上面已经拿到了用户认证码,接着需要登录并初始化页面。 + +初始化页面就是向服务端请求常用的联系人等信息,如下 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): + +```JavaScript +{ +    "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;| + +服务器返回数据: + +```JavaScript +{ + "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是当前登录账户信息。 + +### 2.2、开启消息状态通知 + +接着需要开启消息状态通知。我们可以看到如下 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): + +```JavaScript +{ + "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;| + +服务器返回数据: + +```javascript +{ + "BaseResponse": { + "Ret": 0, + "ErrMsg": "" + }, + "MsgID": "2271xxxxxxxxxxxxx44" +} +``` + +- BaseResponse.Ret表示请求返回状态,0表示成功。 + +### 2.3、服务端状态同步 + +继续观察,我们没间隔一定的时间,浏览器会想服务器发送一个重复的 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:手机操作了微信| + +## 3、联系人管理 + +###3.1、获取全部联系人列表 + +接着可以看到获取全部联系人列表的 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|同前面获取到的;| + +服务器返回数据: + +```javascript +{ +   "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内部字段介绍: + +```javascript + "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": "" +``` + +### 3.2、批量获取指定用户信息 + +然后可以看到批量获取指定联系人信息的 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): + +```javascript +{ + "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。| + +服务器返回数据: + +```javascript +{ + "BaseResponse": { + "Ret": 0, + "ErrMsg": "" + }, + "Count": 2, + "ContactList": [{ + "Uin": 0, + "UserName": "@@76feaa87c635763438059aaeaaa7030c60a09d33", + "NickName": "一啣群)", + "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": "ä½ è", + "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即是获取到的指定的联系人信息。 + +### 3.3、修改联系人备注 + +当我们修改联系人备注的时候,会发现浏览器发送了如下 POST 请求: + +``` +https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxoplog +``` + +POST的数据(JSON): + +```javascript +{ + "BaseRequest": { + "DeviceID": "e81xxxxxxxxx7686", + "Sid": "8rwxxxxxxxxxHq2P", + "Skey": "@crypt_jkde99da_b4xxxxxxxxxxxxxxx76d9yualp", + "Uin": "26xxx7" + }, + "CmdId": 2, + "RemarkName": "新的备注名", + "UserName": "@07a2e8b4a1f98eb78a7xxxxxxxxxxxx5b7bc4908376xxx05917b" +} +``` + +POST参数分析: + +|参数名|示例值|描述| +|---|---|---| +|BaseRequest||基本请求参数,同其它;| +|CmdId|2|固定值;有可能还有其它值来表示不同类型操作。| +|RemarkName||新的备注名;| +|UserName||要修改的联系人的UserName;| + +服务器返回数据: + +```javascript +{ + "BaseResponse": { + "Ret": 0, + "ErrMsg": "" + } +} +``` + +- BaseResponse.Ret表示操作成功。 + +## 4、收发消息 + +### 4.1、从服务端拉取新消息 + +我们发现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): + +```javascript +{ + "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之后都是通过本请求更新;| + +服务端返回数据: + +```javascript +{ + "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:撤回消息 +- SyncKey会暂存起来作为下一次请求的参数。 + +### 4.2、发送消息 + +打开一个聊天界面,向好友发送一条消息,会发现产生如下 POST 请求: + +``` +https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn%253D +``` + +URL参数分析: + +|参数名|示例值|描述| +|---|---|---| +|pass_ticket|AFsdZ7eHxxxxxxxxxxxxxxxxfr1vjHPn%253D|同前面获取的;| + +POST的数据(JSON): + +```javascript +{ + "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|固定值;| + +服务端返回数据: + +```javascript +{ + "BaseResponse": { + "Ret": 0, + "ErrMsg": "" + }, + "MsgID": "7650884298732299102", + "LocalID": "15321964202620841" +} +``` + +- LocalID是发送时指定的LocalID。 +- MsgID是服务端的消息ID。 + +### 4.3、上传媒体到服务器 + +如果我们发送一个图片、文件等媒体类消息,会看到在发送消息请求前有如下 POST 请求: + +``` +https://file.wx.qq.com/cgi-bin/mmwebwx-bin/webwxuploadmedia?f=json +```