订单异步通知修改订单状态

简介: 订单异步通知修改订单状态

订单支付成功后,需要更改订单状态

be41864b8a488f6aa5d43b1587e61aef_202110222243503.png

支付宝有两种回调方式

  • 同步回调:可以直接用request获取订单传回的数据,利用签名验证是否正确再去修改订单状态,但这种方式不推荐也不好,如果浏览器不小心关闭或者用户关闭,导致页面跳转不了也就无法修改订单数据
  • 异步通知:只要支付成功以后就会给我们指定的地址发送一个请求还会带上之前成功的数据,收到以后再去修改订单,比较可靠

对于PC交易用户支付完成,支付宝会根据API传入的notify_url,通过post请求的形式将支付结果作为参数通知到商户系统,例如一些支付参数签名,业务参数支付时间流水号等等

6a18f5c27d8ae117b5faa54ba2be87e3_202110222301518.png

只要我们订单支付成功,支付宝就会发送通知告诉我们订单支付成功了,我们要回复通知不然支付宝会一直尝试给我们发送通知,这也是相当于分布式事务中的最大努力通知机制

环境搭建

要让支付宝访问到我们,就要让我们的服务能够让外网访问到,因此要指定一个地址用来处理成功后支付的请求

#支付成功的异步通知页面
gulimall.alipay.notify_url=http://yjcpds.natappfree.cc/payed/notify

异步回调方法,验证成功就修改订单状态

@RequestMapping("/payed/notify")
    public String handleAlipayed(PayAsyncVo vo, HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {
        Map<String, String[]> map = request.getParameterMap();
//        for(String key : map.keySet()){
//            String value = request.getParameter(key);
//            System.out.println("参数名:"+key+"-->参数值:"+value);
//        }
        //阿里验签方法
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            //乱码解决,这段代码在出现乱码时使用
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayTemplate.getAlipay_public_key(),
                alipayTemplate.getCharset(), alipayTemplate.getSign_type());
        if (signVerified) {
            System.out.println("签名验证成功...");
            String result = orderService.handlePayResult(vo);
            return result;
        } else {
            System.out.println("签名验证失败...");
            return "error";
        }
    }

内网穿透联调

c660a7630f233deace5703f09f38ede8_202110222309270.png

需要把外网地址 http://yjcpds.natappfree.cc映射到我们内网主机的order.gulimall.com中

先去设置内网穿透映射的内网地址

82137555fb1c3e84cf1f917b746b81f7_202110222311411.png

进入到内网,内网配置了host地址,进入了虚拟机80端口

nginx监听到80端口,然后根据请求路径需要转给订单服务,但是由于请求头的原因找不到订单服务,因此进行精准匹配,把这个payed请求,直接转给订单服务,nginx还需要识别请求进来的主机名,需要配置内网穿透映射的主机名

26fdbbb18b612c70d7114e0d110b4f15_202110222315812.png

最后编写响应成功修改订单的逻辑

@Override
    public String handlePayResult(PayAsyncVo vo) {
        //1.保存交易流水
        PaymentInfoEntity infoEntity = new PaymentInfoEntity();
        infoEntity.setAlipayTradeNo(vo.getTrade_no());
        infoEntity.setOrderSn(vo.getOut_trade_no());
        infoEntity.setPaymentStatus(vo.getTrade_status());
        infoEntity.setCallbackTime(vo.getNotify_time());
        paymentInfoService.save(infoEntity);
        //2.修改订单状态
        if(vo.getTrade_status().equals("TRADE_SUCCESS")||vo.getTrade_status().equals("TRADE_FINISHED")){
            //支付成功
            String outTradeNo = vo.getOut_trade_no();
            this.baseMapper.updateOrderStatus(outTradeNo,OrderStatusEnum.PAYED.getCode());
        }
        return "success";
    }

到此整个流程就完毕了,支付成功利用异步回调方法修改订单状态,完成整个支付流程

收单

1、订单在支付页,不支付,一直刷新,订单过期了才支付,订单状态改为已支付了,但是库存解锁了

0ba5df0ba67d987034e40cf1b4e67b2a_202110222323469.png

  • 使用支付宝自动收单功能解决。只要一段时间不支付,就不能支付了
    在下单接口中增加一个参数,超时关闭订单支付
    8021d36ef6a9835b9013863ddf82585f_202110222325709.png

2、由于时延等问题。订单解锁完成,正在解锁库存的时候,异步通知才到

订单快要过期的时候,我们正好支付了,但是订单正好过期了,库存也解锁了

  • 订单解锁,手动调用收单
    e45674cee53aad4ceea23b6a2bd533d5_202110222329769.png

3、网络阻塞问题,订单支付成功的异步通知一直不到达

  • 查询订单列表时,ajax获取当前未支付的订单状态,查询订单状态时,再获取一下支付宝此订单的状态

4、其他各种问题

  • 每天晚上闲时下载支付宝对账单,一一进行对账
相关文章
支付系统39----支付宝支付,定时查单,每隔30秒执行1次,查询超过5分钟,并且未支付的订单
支付系统39----支付宝支付,定时查单,每隔30秒执行1次,查询超过5分钟,并且未支付的订单
|
NoSQL Java Redis
服务端如何防止订单重复支付!
如图是一个简化的下单流程,首先是提交订单,然后是支付。 支付的话,一般是走支付网关(支付中心),然后支付中心与第三方支付渠道(微信、支付宝、银联)交互。 支付成功以后,异步通知支付中心,支付中心更新自身支付订单状态,再通知业务应用,各业务再更新各自订单状态。
服务端如何防止订单重复支付!
|
8月前
|
消息中间件 NoSQL Kafka
订单超时取消的11种方式(非常详细清楚)
订单超时取消的11种方式(非常详细清楚)
3339 2
订单超时取消的11种方式(非常详细清楚)
支付系统42----支付宝支付-定时查单-订单已支付,如果我们在定时查单的状态中,我们明明已经支付的订单,却在本地状态中显示没有支付,这是因我们的异步通知因为种种原因没有接受到,支付宝端成功,本地失败
支付系统42----支付宝支付-定时查单-订单已支付,如果我们在定时查单的状态中,我们明明已经支付的订单,却在本地状态中显示没有支付,这是因我们的异步通知因为种种原因没有接受到,支付宝端成功,本地失败
支付系统34----支付成功异步通知,处理重复通知,我们在我们程序当中找到处理订单的processOrder方法,我们要在更新订单状态和记录日志之前,先处理重复通知
支付系统34----支付成功异步通知,处理重复通知,我们在我们程序当中找到处理订单的processOrder方法,我们要在更新订单状态和记录日志之前,先处理重复通知
|
6月前
|
JSON 数据格式
支付系统41----定时查单-订单未支付
支付系统41----定时查单-订单未支付
|
6月前
|
SQL 数据库
支付系统32-------支付宝支付-----支付成功异步通知----更新订单状态记录支付日志
支付系统32-------支付宝支付-----支付成功异步通知----更新订单状态记录支付日志
|
8月前
|
消息中间件 Java Unix
MQ产品使用合集之消费订单状态,订单消费待支付消息失败,是否会导致其他订单也没法消费
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
118 1
|
消息中间件 NoSQL Java
订单超时取消的11种方法(上)
大家好,我是三友~~ 延迟任务在我们日常生活中比较常见,比如订单支付超时取消订单功能,又比如自动确定收货的功能等等。 所以本篇文章就来从实现到原理来盘点延迟任务的11种实现方式,这些方式并没有绝对的好坏之分,只是适用场景
订单超时取消的11种方法(上)