缘起
公司有个服务做埋点收集的,可以参考我之前的文章埋点日志最终解决方案,今天突然发现有些数据日志可以输出,但是没法入库。
多出的双引号
查看Flink日志发现了JSON解析失败,Flink是从Kafka拿数据,Kafka本身不处理数据,Kafka前面是埋点收集服务,这个服务是SpringWebFlux+ReactorKafka做的,收集到数据后对数据做一些解码或解密(如UrlDecode,Base64Decode或者Aes解密等),写入日志并且扔进Kafka。查看日志发现类似以下内容:
# 省略了大部分字段,只为说明问题
"{"client":"xcx","os":"windows","ip":"192.168.1.1","xx":"xxxx"}"
"{"client":"xcx","os":"Macos","ip":"192.168.1.1","xx":"xxxx"}"
明显看出前后各多了一个双引号。
场景复现
仔细比对了大量日志,发现只有MacOS和Windows下的微信打开小程序时会出现这个问题,安卓,iOS系统的微信小程序不会出现这个问题,分别使用了一台MacOS和Windows,成功复现
SpringWebFlux的HttpMessageConverter捣的鬼???
顺着日志输出的往上找,有一个UrlDeocde
操作,仔细测试了下这个UrlDeocde
步骤,发现不会自动产生双引号。我第一个想到的就是SpringMVC
如果HttpMessageConverter
使用不当就导致这个问题,尤其是想使用FastJson
序列化JSON但没处理Jackson
,这俩同时存在的时候,会多出双引号。于是我在Controller
里面对应的方法下了一个断点。
@PostMapping(value = "/receive/xcx")
public Mono<ResultBase<String>> receiveXcx(@RequestBody Mono<String> body) {return xcxKafkaSink.sendRecord(body).map(ResultBase::of); //这一行下断点
}
从这个点开始回溯发现SpringWebFlux
和SpringMVC
差距太大,这个Reactor
风格的异步调用链,真是看不出中间干了啥,更别提找到HttpMessageConverter
在哪执行的,后来找到了HttpMessageConverter
的实现类,在对应的方法read()
中都下了断点,根本没走到断点。
我在xcxKafkaSink.sendRecord(body)
加了一行输出日志打印了一下body,发现当前端传入双引号时会这里会出现双引号,当前端不传入双引号时,这里就没有双引号,证明了问题大概率出在请求方。
后来和架构聊了下发现以上存在2个问题:
SpringWebFlux
是异步的,在Controller
的方法下断点根本没用,因为RequestBody
走到Controller
这里还没使用,数据还在Buffer
中,根本没有读取,就不会走HttpMessageConverter
,所以在HttpMessageConverter
的实现类中下断点根本走不到,需要经过数据使用的那里理论上才会走HttpMessageConverter
链。(我后来有去找过在哪调用HttpMessageConverter
,没找到所谓的HttpMessageConverter
链,可能需要好好了解SpringWebFlux
原理才能知道在哪吧)- 只有Windows和MacOS下微信小程序会有这个问题,安卓和iOS下都没有,说明大概率不是后端的问题。
抓包显露真凶
如果服务端没法看出来啥问题,那就直接从客户端入手,试试能不能看到客户端请求时body体里面带了双引号。
从网上找了找资料,发现国产的ProxyPin
比较好用,于是下载使用。
地址:https://github.com/wanghongenpin/network_proxy_flutter/releases
我的电脑是M2芯片的MacOS,下载对应的包即可。
- 打开提示包损坏,去设置->隐私里点仍要打开即可
- 打开后点击最上方的锁标志,打开启用HTTPS代理,然后点安装根证书到本机,按提示安转并信任根证书。
- 打开微信小程序,触发问题
- ProxyPin中查找抓到的包,查看请求体,清楚的看到请求时前后都有引号