微信机器人API接口开发中Java后端的接口联调与抓包分析实战技巧
·
微信机器人API接口开发中Java后端的接口联调与抓包分析实战技巧
1. 联调环境搭建:本地代理 + HTTPS解密
微信机器人通常通过企业微信或第三方协议接收消息,回调地址需公网 HTTPS。开发阶段使用 ngrok + mitmproxy 组合实现本地调试:
# 启动内网穿透
ngrok http 8080
# 启动抓包代理(监听8081,生成CA证书)
mitmproxy -p 8081 --set ssl_insecure=true
在 Java 应用启动参数中配置代理:
-Dhttp.proxyHost=localhost -Dhttp.proxyPort=8081 \
-Dhttps.proxyHost=localhost -Dhttps.proxyPort=8081 \
-Djavax.net.ssl.trustStore=/path/to/mitmproxy-ca-cert.jks
2. 拦截并记录所有出入站请求
自定义 LoggingInterceptor 记录原始报文:
package wlkankan.cn.wechat.robot.interceptor;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class FullTrafficLoggingInterceptor implements Interceptor {
private static final Logger log = LoggerFactory.getLogger("TRAFFIC");
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long start = System.nanoTime();
// 记录请求
log.debug("→→→ {} {}{}", request.method(), request.url(),
request.body() != null ? "\n" + bodyToString(request) : "");
Response response = chain.proceed(request);
long tookMs = (System.nanoTime() - start) / 1_000_000;
// 记录响应
String responseBody = response.peekBody(1024 * 1024).string();
log.debug("←←← {} {} ({} ms)\n{}",
response.code(), response.message(), tookMs, responseBody);
return response.newBuilder()
.body(ResponseBody.create(responseBody, response.body().contentType()))
.build();
}
private String bodyToString(Request request) {
try {
Request copy = request.newBuilder().build();
if (copy.body() == null) return "";
Buffer buffer = new Buffer();
copy.body().writeTo(buffer);
return buffer.readUtf8();
} catch (IOException e) {
return "failed to read body";
}
}
}
注册到 OkHttpClient:
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new FullTrafficLoggingInterceptor())
.build();

3. 模拟微信回调请求进行本地测试
编写测试工具类直接触发 Controller:
@SpringBootTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class CallbackSimulationTest {
@Autowired
private MockMvc mockMvc;
@Test
void simulateWeComTextMessage() throws Exception {
String encryptedXml = """
<xml>
<ToUserName><![CDATA[ww1234567890ab]]></ToUserName>
<FromUserName><![CDATA[zhangsan]]></FromUserName>
<CreateTime>1700000000</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[测试消息]]></Content>
<MsgId>1234567890</MsgId>
</xml>
""";
// 构造签名参数(开发模式可跳过校验)
mockMvc.perform(post("/robot/callback/ww1234567890ab")
.param("msg_signature", "dummy_sign")
.param("timestamp", "1700000000")
.param("nonce", "abcd1234")
.content(encryptedXml)
.contentType(MediaType.APPLICATION_XML))
.andExpect(status().isOk())
.andExpect(content().string("success"));
}
}
4. 解析并验证加密消息体
企业微信回调使用 AES 加密,需正确解密:
@Service
public class WeComCryptoService {
public String decrypt(String encrypt, String corpId) {
try {
byte[] aesKey = Base64.getDecoder().decode(config.getEncodingAesKey() + "=");
SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(aesKey, 0, 16));
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encrypt));
// 去除随机前缀和尾部corpid
int pad = decrypted[16];
int xmlEnd = decrypted.length - 20 - pad;
return new String(decrypted, 20, xmlEnd - 20, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new SecurityException("解密失败", e);
}
}
}
在 Controller 中调用:
@PostMapping(value = "/callback/{corpId}", consumes = MediaType.APPLICATION_XML_VALUE)
@ResponseBody
public String handleCallback(@PathVariable String corpId,
@RequestParam String msg_signature,
@RequestParam String timestamp,
@RequestParam String nonce,
@RequestBody String encryptedXml) {
// 验证签名(略)
String plainXml = weComCryptoService.decrypt(extractEncrypt(encryptedXml), corpId);
// 解析 plainXml 并处理
return "success";
}
5. 使用 Wireshark 辅助分析二进制协议
若对接的是 iPad 协议等私有 TCP 流,启动 Wireshark 抓包:
# 过滤目标IP和端口
tcp.port == 8080 and ip.addr == 127.0.0.1
在 Java 代码中添加唯一追踪 ID 便于过滤:
public class MessageSender {
public void sendToDevice(String content) {
String traceId = UUID.randomUUID().toString().replace("-", "");
log.info("[TRACE] Sending message with traceId={}", traceId);
Map<String, Object> payload = new HashMap<>();
payload.put("trace_id", traceId);
payload.put("content", content);
httpClient.post("/send", payload); // 此ID会出现在TCP载荷中
}
}
在 Wireshark 中搜索 traceId 即可定位完整交互流。
6. 联调问题快速定位 checklist
- ✅ 回调 URL 是否能被微信服务器访问(通过 ngrok 公网地址);
- ✅ 签名算法是否与文档一致(注意排序、URL 编码);
- ✅ AES 解密是否使用 PKCS7(需 BouncyCastle Provider);
- ✅ 响应是否为纯文本
"success"(不能带 JSON 或空格); - ✅ 日志是否开启 DEBUG 级别记录完整请求体。
通过代理抓包、请求模拟、加密解析、流量标记与工具链组合,可在复杂微信机器人 API 对接中快速复现、定位并修复联调问题,显著缩短开发周期。
更多推荐



所有评论(0)