转至元数据结尾
转至元数据起始

今天,企微告警群里报有如下几个相同的程序异常。

不难分析出来,是Fastjson反序列化数据的过程中,将字符串转换为Long类型的orderNo时出现了异常。通常这种情况,不外乎“字符串不是有效Long数字”这个原因。例如,空串、“abc”是无法转换为Long的,再例如,一个超长的数字字符在转换为Long时,可能出现数据越界异常。

我们来看其中一个Trace的异常堆栈。的确是因字符串超出Long数据范围导致Fastjson转换错误。

2024-10-09 09:15:53.367 [server-provider-10.244.7.218] [TID:555bbd00d1404e04a98b8d773a248882.241.17284365533270487] [DubboServerHandler-10.244.7.218:20880-thread-177] INFO c.e.b.m.c.provider.pay.PaymentQueryServiceImpl:78 - 
*****批量付款查询接口参数:{"funCode":"6002","ip":"114.135.116.1","merId":"1723705456764793","reqData":"{\"merBatchId\":\"YW2024090413159623124\",
\"queryItems\":[{\"merOrderId\":\"YW2024090413159623124\",\"orderNo\":\"131000708095401500277312024090485491783856\"}]}","reqId":"202410090915535298","reqTime":1728436553330,"sign":"******","version":"V1.0"}

2024-10-09 09:15:53.367 [server-provider-10.244.7.218] [TID:555bbd00d1404e04a98b8d773a248882.241.17284365533270487] [DubboServerHandler-10.244.7.218:20880-thread-177] ERROR c.e.b.m.c.provider.pay.PaymentQueryServiceImpl:? - 
*****批量付款查询接口异常:com.alibaba.fastjson.JSONException: parseLong error, field : orderNo
	at com.alibaba.fastjson.serializer.LongCodec.deserialze(LongCodec.java:86)
	at com.alibaba.fastjson.parser.deserializer.DefaultFieldDeserializer.parseField(DefaultFieldDeserializer.java:88)
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.parseField(JavaBeanDeserializer.java:1278)
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:893)
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.parseRest(JavaBeanDeserializer.java:1624)
	at com.alibaba.fastjson.parser.deserializer.FastjsonASMDeserializer_12_PaymentQueryItemsVO.deserialze(Unknown Source)
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:287)
	at com.alibaba.fastjson.parser.deserializer.FastjsonASMDeserializer_11_PaymentQueryVO.deserialze(Unknown Source)
	at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:287)
	at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:705)
	at com.alibaba.fastjson.JSON.parseObject(JSON.java:394)
	at com.emaxcard.boss.modules.clientapi.provider.pay.PaymentQueryServiceImpl.business(PaymentQueryServiceImpl.java:84)
	at com.emaxcard.boss.modules.clientapi.provider.CommonClientServiceImpl.business(CommonClientServiceImpl.java:51)
	at com.emaxcard.boss.modules.clientapi.provider.CommonClientServiceImpl$$FastClassBySpringCGLIB$$2784a2b7.invoke(<generated>)
	...
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	...
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
	at com.emaxcard.boss.modules.clientapi.provider.CommonClientServiceImpl$$EnhancerBySpringCGLIB$$efd97254.business(<generated>)
	at com.emaxcard.boss.modules.clientapi.CommonClientServiceDubboWrap13.invokeMethod(CommonClientServiceDubboWrap13.java)
	at org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker.invoke...
	at com.emax.zhenghe.common.filters.ProviderExceptionFilter.invoke...
	at org.apache.dubbo.rpc.filter...
	at org.apache.dubbo.rpc.cluster.filter...
	at org.apache.dubbo.monitor.support...
	at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:86)
	at org.apache.dubbo.monitor.support...
	at org.apache.dubbo.rpc.filter...
	at org.apache.dubbo.rpc.cluster...
	at java.lang.Thread.run(Thread.java:745)
Caused by: com.alibaba.fastjson.JSONException: can not cast to long, value : 131000708095401500277312024090485491783856
	at com.alibaba.fastjson.util.TypeUtils.castToLong(TypeUtils.java:908)
	at com.alibaba.fastjson.serializer.LongCodec.deserialze(LongCodec.java:79)
	... 79 common frames omitted





上面是纯Java技术层面的分析。


接下来,我们来分析程序。

代码位置 PaymentQueryServiceImpl.java:84。PaymentQueryServiceImpl 在 bosskg-server-provider服务里,用来处理 商户API查单。


我们来回答一个问题:API接口接收到参数后,要不要对请求参数做校验?

答案自然是:要。


继续发问:要做哪些校验?

回答这个问题,需要你调动上千个脑细胞。

本案中涉及的是参数的有效性校验。即:订单号必须是有效的Long数字。

显然,这个 PaymentQueryServiceImpl 不称职,它未对orderNo做合法性校验,直接交给了JVM运行时。

那么,PaymentQueryServiceImpl 该怎么改呢?

(暂略)


OK,PaymentQueryServiceImpl 是改完了。

接下来,继续发问:API接口接收到参数后,应该在哪层做参数校验?

答案是:在API接口层。

bosskg是分布式系统,因此,参数校验是 bosskg-client-api 的职责,而不是 作为rpc服务的 bosskg-server-provider 的职责。

继续发问:如果bosskg是单体系统,参数校验应该放在哪层?

(暂略)








编写评论...