• 你以为你以为的就是你以为的吗?记一次服务器点对点通知的联调过程


    公司两个系统:⒈. 我们项目组负责的A系统 、 ⒉. 另一个项目组负责的B系统。

    A系统要调用B系统接口上送业务签约单申请。B系统接收数据后,异步处理,签约完成后,会主动发送通知给A系统。

    在联调异步通知接口时,问题来了,发现我方一直收不到对方的回调。

    接口文档里说明了,通过http协议的post请求来发送异步通知,报文是json格式字符串。

    我们A系统定义restful的http接口。

    【题外话】@RequestBody注解:@RequestBody接收的参数是来自requestBody中,即请求体。适用于http post请求。请求端通过HttpEntity传递参数,并在请求头中声明数据的类型Content-Type,SpringMVC通过使用 HandlerAdapter 配置的HttpMessageConverters来解析HttpEntity中的数据,然后绑定到相应的bean上。

    @RestController
    @Slf4j
    public class TaxNotifyController {
    
        @Reference
        private TaxNotifyService taxNotifyService;
    
        /**
         *
         * @param notifyVO
         * @return
         */
        @PostMapping("/ayncNotify")
        @UnAuthToken
        public String ayncNotify(@RequestBody NotifyVO notifyVO){
            log.info("收到回调----异步回调----异步通知----回调通知:{}", JSON.toJSONString(notifyVO));
            String respText = taxNotifyService.ayncNotify(notifyVO);
            log.info("回调----异步回调----异步通知----回调通知 回写内容:{}",respText);
            return respText;
        }
    }

    QA在测试过程中,发现对方B系统有请求,如下日志截图为证。而查看我方A系统的log文件,却并没有发现“收到回调----异步回调----异步通知----回调通知”这样的log。也就是说,我方A系统一直收不到请求。

    难道是B系统到我们A系统的网络不通?双方都是测试环境呀!还是去找运维确认吧。运维在B系统服务器执行curl验证结果如下。因为需要POST,所以curl接收到这个错误。但至少证明这2个系统间的网络是没问题的。

    [root@localhost logs]# curl http://192.168.40.84:8802/ent-boot/ayncNotify
    {"code":"ERROR","message":"Request method 'GET' not supported"}

    然后,然后,再次确认我方log。发现蛛丝马迹:

    2019-12-13 11:07:01.894 [http-nio-8802-exec-9] INFO  com.emaxcard.car.filter.CrosXssFilter:40 - 
    CrosXssFilter.......orignal url:/ent-boot/ayncNotify,ParameterMap:{} 2019-12-13 11:07:01.895 [http-nio-8802-exec-9] WARN o.s.w.s.m.support.DefaultHandlerExceptionResolver:197 -
    Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'text/xml;charset=UTF-8' not supported] 2019-12-13 11:07:01.895 [http-nio-8802-exec-9] INFO com.emaxcard.car.filter.CrosXssFilter:44 -
    CrosXssFilter..........doFilter url:/ent-boot/ayncNotify,ParameterMap:{}

    莫非,对方给的content-type是text/xml??

    找B系统的开发同学,经查代码里HttpUtil,果然,指定的content-type是text/xml。 如下图。我们知道,springmvc默认接收数据的格式是json方式序列化的。你指定成xml格式,显然springmvc在反序列化成NotifyVO对象时会抛出异常。自然,就不会执行这个action方法了,所以,我们没看到那条“收到回调----异步回调----异步通知----回调通知”log。

    【题外话】关于springmvc的messageconverter设置,可以查看spirng-web.jar里的RestTemplate.java源码。

    Line122:jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);

    接着说,我们让这位开发同学改成 application/json 后,问题得以解决。

    But,yet,however,下午,QA在测试付款单的回调的时候,同样的问题又出现了,我们接收不到请求报文。一看log,又是text/xml搞的鬼。B系统的这个付款回调是另一个同学开发的。考虑到目前已经有外部商户接入B系统,他们不准备改了。

    不改就不改吧,B系统他们不改,只好我们A系统改了。话说回来,即便他们现在不改,日后有其他商户对接联调时,也难免会出现类似的问题。那,就是以后的事儿了。

    我们怎么改呢?那就不直接从RequestBody里接收NotfiyVO对象了,改成接收String字符串。然后,在方法里来做判断和反序列化。改后的代码为:

        @PostMapping("/ayncNotify")
        @UnAuthToken
        public String ayncNotify(@RequestBody String notifyStr){
            log.info("收到回调----异步回调----异步通知----回调通知:{}", notifyStr);
            if(StringUtils.isBlank(notifyStr)){
                log.info("回调通知为空");
                return "ERROR-回调通知请求参数为空";
            }
            NotifyVO notifyVO = JSON.parseObject(notifyStr,NotifyVO.class);
            log.info("回调转换NotifyVo:{}",notifyVO);
            String respText = taxNotifyService.ayncNotify(notifyVO);
            log.info("回调----异步回调----异步通知----回调通知 回写内容:{}",respText);
            return respText;
        }

    THE END.

    下午得知,一同学在对接付款接口时,当付款接口返回受理失败时,他把付款单的付款结果改成了失败。这可要不得呀!付款结果一定要通过付款查询接口来查。查询返回付款成功,则付款成功;查询返回付款失败,则付款失败;对于查询到的其他结果,保守起见,都视为付款中即可,然后继续查询,查询次数达到阈值则交由人工来干预。技术人员千万别自作主张,把某些不明确的结果定为付款失败。万一出现重复付款,那就尴尬了。我在2016年那时刚开始做聚合支付时,是有这样的惨痛经历的。

     ☞ Stay Hungry,Stay Foolish. 

  • 相关阅读:
    扁鹊见蔡桓公
    月出
    TypeScript 基本类型
    随机漂浮图片广告实例代码
    js实现的随机颜色实例代码
    初识JavaScript 变量, 操作符, 数组
    HTML5的新结构标签
    14款超时尚的HTML5时钟动画
    CSS如何设置div半透明效果
    Google Doodle 2015圣诞版背后的故事与十年圣诞回顾
  • 原文地址:https://www.cnblogs.com/buguge/p/12035854.html
Copyright © 2020-2023  润新知