个人微信安全合规使用官方iLink协议零依赖裸调API实战指南
需要项目源码 可以私信我~本目录是腾讯微信官方个人 Bot APIiLink 协议的零依赖裸调实现。每个接口一个独立.py文件只用 Python 标准库http.client填好参数python xxx.py即可运行不依赖任何第三方包、也不依赖本项目其它代码。api/—— 7 个协议接口每个一个文件callback.py—— 常驻循环收消息iLink 无 webhook长轮询即回调接入域名https://ilinkai.weixin.qq.com目录整体流程三个固定套路必读接口逐一说明1. get_bot_qrcode 取登录二维码2. get_qrcode_status 判断是否登录成功3. callback.py 持续收消息4. sendmessage 发消息5. getconfig 取 typing_ticket6. sendtyping 发输入状态7. getuploadurl 发图片/文件完整跑通示例常见问题一、整体流程┌─ 登录一次性拿 bot_token───────────────────────────────┐ │ ① get_bot_qrcode.py → 拿 qrcode 二维码URL渲染给用户扫 │ │ ② get_qrcode_status.py → 轮询statusconfirmed 时拿 bot_token│ └──────────────────────────────────────────────────────────────┘ │ 保存 bot_token ▼ ┌─ 运行常驻收发消息─────────────────────────────────────┐ │ ③ callback.py → 长轮询持续收消息自动滚动游标 │ │ ④ sendmessage.py → 回复消息带回 context_token │ │ 可选 ⑤ getconfig → ⑥ sendtyping → 发正在输入 │ │ 可选 ⑦ getuploadurl CDN 上传 → 发图片/文件 │ └──────────────────────────────────────────────────────────────┘接口与文件对照#文件路径鉴权作用1api/get_bot_qrcode.pyGET/ilink/bot/get_bot_qrcode无取登录二维码2api/get_qrcode_status.pyGET/ilink/bot/get_qrcode_status无判断是否登录成功3callback.pyPOST/ilink/bot/getupdatesBearer长轮询收消息4api/sendmessage.pyPOST/ilink/bot/sendmessageBearer发消息5api/getconfig.pyPOST/ilink/bot/getconfigBearer取 typing_ticket6api/sendtyping.pyPOST/ilink/bot/sendtypingBearer发/取消正在输入7api/getuploadurl.pyPOST/ilink/bot/getuploadurlBearer发媒体前取 CDN 上传参数二、三个固定套路必读登录后的所有接口都绕不开这三点看懂它们再看具体接口就很轻松。套路 1Bearer 鉴权登录成功拿到bot_token后所有接口都要带这两个头AuthorizationType:ilink_bot_token,# 固定值Authorization:fBearer{TOKEN},# TOKEN 是 bot_token⚠️bot_token是一串 ASCII形如a46b...im.bot:0600...。如果你把中文占位符当成 token 直接跑会报UnicodeEncodeError: latin-1 codec cant encode...—— 这不是 bug是 token 没填对。HTTP 头只能是 ASCII。套路 2X-WECHAT-UIN每次随机防重放登录后的接口都要带这个头。构造方式很特别随机 uint32 → 转十进制字符串 → base64importbase64,secretsdefrandom_wechat_uin()-str:uint32int.from_bytes(secrets.token_bytes(4),big)returnbase64.b64encode(str(uint32).encode(utf-8)).decode(ascii)注意是先把数字转成十进制字符串再 base64不是直接对 4 字节做 base64。套路 3context_token回复时必须原样带回每条收到的消息都带一个context_token。你回复时必须把它原样填进sendmessage否则消息关联不到正确的对话窗口会发失败或发错地方。# 收到消息context_tokenmsg[context_token]# 回复时带上payload{msg:{...,context_token:context_token}}三、接口逐一说明1.get_bot_qrcode.py— 取登录二维码无需鉴权。登录第一步。python api/get_bot_qrcode.py返回两个关键字段字段用途qrcode轮询凭据传给第 2 步get_qrcode_statusqrcode_img_content二维码里要编码的 URL把它渲染成二维码图给用户扫qrcode和qrcode_img_content是两个不同的东西别混用前者给程序轮询用后者是给人扫的二维码内容。把qrcode_img_content转二维码可用任意库例如importqrcode qrcode.make(qrcode_img_content).save(login.png)# 然后让用户扫这张图2.get_qrcode_status.py— 判断是否登录成功无需鉴权。登录第二步。把第 1 步拿到的qrcode填进文件顶部的QRCODE然后循环调用判断状态。服务器是长轮询会 hold 住最多 35 秒。# 先编辑文件把 QRCODE ... 改成第1步的 qrcodepython api/get_qrcode_status.pystatus四种取值status含义该做什么wait还没扫继续轮询scaned已扫待手机端确认继续轮询expired二维码过期回到第 1 步重新取码confirmed登录成功取出bot_token保存停止轮询confirmed时返回字段说明bot_token后续所有请求的 Bearer token务必保存ilink_bot_idbot 账号 IDxxxim.botbaseurl后续请求的 base URLilink_user_id扫码用户的 IDxxxim.wechat3.callback.py— 持续收消息回调iLink 没有 webhook 推送收消息靠不停调用getupdates长轮询——这个常驻循环就等价于回调。用前先改文件顶部的TOKEN为登录拿到的bot_token然后python callback.py它会不断调getupdates服务器每次最多 hold 35 秒自动滚动get_updates_buf游标关键不滚动会重复收到消息处理会话过期errcode-14提示重新登录和失败退避连续失败 3 次退避 30 秒对每条消息调用handle_message()打印内容接你自己的业务只改handle_message()这一个函数defhandle_message(msg:dict)-None:ifmsg.get(message_type)notin(None,1):# 只处理用户消息returntextextract_text(msg)# 提取文本context_tokenmsg.get(context_token)# 回复要用from_usermsg.get(from_user_id)# 你的逻辑比如调 AI 生成回复再调 sendmessage 发出去print(f{from_user}说:{text})每条消息item_list[].type类型1文本2图片3语音4文件5视频。extract_text()已帮你把这些抽成可读字符串。4.sendmessage.py— 发消息发文字/图片/文件/视频/语音。文件顶部填好TOKEN、TO_USER_ID、CONTEXT_TOKEN、TEXT后运行。python api/sendmessage.py请求体msg关键字段字段值说明to_user_idxxxim.wechat发给谁message_type22BOT 发出message_state22FINISH 完整消息context_token从收到消息取必填否则关联不到对话item_list[{type:1, text_item:{text:...}}]消息内容收发配合callback.py的handle_message里拿到msg[context_token]填进sendmessage.py的CONTEXT_TOKEN即可回复同一对话。5.getconfig.py— 取 typing_ticket发正在输入状态前需要先拿typing_ticket。python api/getconfig.py返回{ ret: 0, typing_ticket: base64 }把typing_ticket传给 sendtyping。6.sendtyping.py— 发正在输入状态python api/sendtyping.py字段说明typing_ticket从 getconfig 拿到status1正在输入2取消典型用法调 AI 前发status1回复发出后发status2长任务期间每 5 秒重发status1保活。7.getuploadurl.py— 发图片/文件发媒体比发文本多几步因为微信 CDN 上的文件都经过AES-128-ECB 加密。getuploadurl.py已经帮你算好文件 MD5、密文大小、随机 key。完整 5 步1. 读文件 → 明文大小 rawsize、明文 MD5 rawfilemd5 2. 生成随机 16 字节 aeskeyAES-128-ECB(PKCS7) 加密 → 密文大小 filesize filesize ceil((rawsize1)/16)*16 3. getuploadurl.py → 拿到 upload_param、filekey、aeskey 4. POST 加密后的密文到 CDN: https://novac2c.cdn.weixin.qq.com/c2c/upload ?encrypted_query_paramupload_paramfilekeyfilekey 响应头 x-encrypted-param 即下载参数 encrypt_query_param 5. sendmessage 的 item_list 填 CDN 引用: { type: 2, image_item: { media: { encrypt_query_param: 上一步的x-encrypted-param, aes_key: base64(aeskey的hex字符串), encrypt_type: 1 }, mid_size: 密文字节数 } }第 2、4 步的 AES 加密和 CDN 上传不是 iLink 协议接口走独立 CDN 域名。如果嫌麻烦本项目移植包openclaw_weixin/cdn/里有现成的upload_file_to_weixin()一行搞定整条链路。裸调版仅演示 getuploadurl 这一步。四、完整跑通示例第一次登录# 1. 取码python api/get_bot_qrcode.py# 复制输出里的 qrcode 和 qrcode_img_content# 把 qrcode_img_content 转成二维码图用微信扫# 2. 判断登录先把 get_qrcode_status.py 里 QRCODE 改成上面的 qrcodepython api/get_qrcode_status.py# 扫码确认后输出 statusconfirmed复制 bot_token之后收发消息# 3. 把 bot_token 填进 callback.py 的 TOKEN启动收消息python callback.py# 现在发消息给这个微信 bot终端就会打印出来# 每条消息带 from_user_id 和 context_token# 4. 回复把 TOKEN / TO_USER_ID(from_user_id) / CONTEXT_TOKEN / TEXT# 填进 sendmessage.py运行python api/sendmessage.py做成自动应答 bot在callback.py的handle_message()里拿到文本后调用你的 AI再用 sendmessage 的逻辑把回复发回去带上context_token即可。五、常见问题Q运行报UnicodeEncodeError: latin-1 codec cant encodeATOKEN还是中文占位符没改。填成真实的bot_tokenASCII 串即可。callback.py已在启动时做校验会给出友好提示。Q消息收到了但回复发不出去 / 发错对话A检查sendmessage是否带了正确的context_token——必须是该条消息里原样取来的。Q一直收到重复的旧消息Aget_updates_buf游标没滚动。callback.py已自动处理若你自己写循环务必每次把响应的get_updates_buf存下来带入下次请求。Q突然收不到消息返回 errcode-14A会话过期需重新扫码登录回到第 1、2 步拿新的bot_token。QHOST 填什么A默认ilinkai.weixin.qq.com。若登录返回了baseurl用它去掉https://前缀。Q怎么验证已有 token 还有没有效A没有专门接口。拿 token 调一次getupdates返回-14就是过期了。