微信公众号支付--3--接收微信支付异步通知

在JSAPI支付官方文档https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6里面,微信团队明确指出,在微信浏览器里面打开H5网页中执行JS调起支付时,代码里面res.err_msg这个值将在用户支付成功后返回ok,但并不保证它绝对可靠,因此,用户支付是否成功不能在这里进行判断,而应该通过接收微信的异步通知来实现。

https://blog.csdn.net/hjfcgt123/article/details/104244974这篇微博中,我们配置文件中有一个属性名为:wechat.notifyUrl。这个参数的作用是什么呢?在生成预支付订单时,请求参数中有一个属性值叫做notify_url,此属性值必传,微信官方指出该属性为:异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。

当支付成功之后,微信会向该url发起异步通知,返回订单的支付状态。我们需要在这里判断订单是否支付成功,继而做其他业务逻辑操作。

一、官方文档

官方文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8

二、代码实现

1、controller

@Controller
@RequestMapping("/pay")
public class PayController {

    @Autowired
    private PayService payService;


    @PostMapping("notify")
    public ModelAndView notify(@RequestBody String notifyDate) {
        //接收微信支付异步通知
        payService.notify(notifyDate);
        //返回给微信处理结果
        return new ModelAndView("pay/success");
    }
   
}

2、service实现类

@Service
@Slf4j
public class PayServiceImpl implements PayService {

    private static final String orderName = "微信点餐订单";

    @Autowired
    private BestPayServiceImpl bestPayService;
    @Autowired
    private OrderService orderService;


    @Override
    public PayResponse notify(String notifyDate) {
        /**
         * 接收微信支付异步通知
         * 1、验证签名(sdk已经内部实现)
         * 2、订单的支付状态(sdk已经内部实现)
         */
        PayResponse payResponse = bestPayService.asyncNotify(notifyDate);
        log.info("【微信支付】异步通知,payResponse={}", JsonUtils.toJson(payResponse));
        /**
         * 3、校验订单是否存在
         */
        OrderDTO orderDTO = orderService.findOne(payResponse.getOrderId());
        if (ObjectUtils.isEmpty(orderDTO)) {
            throw new SellException(ResultEnum.ORDER_NOT_EXIST);
        }
        /**
         * 4、校验订单是否已经被支付
         */
        if (orderDTO.getPayStatus().equals(PayStatusEnum.SUCCESS.getCode())) {
            return payResponse;
        }
        /**
         * 5、判断金额是否一致
         */
        if (!MathUtils.equals(payResponse.getOrderAmount(), orderDTO.getOrderAmount().doubleValue())) {
            log.error("【微信支付】异步通知,订单金额不一致,orderId={},微信通知金额={},系统金额={}",
                    payResponse.getOrderId(),
                    payResponse.getOrderAmount(),
                    orderDTO.getOrderAmount());
            throw new SellException(ResultEnum.WXPAY_NOTIFY_MONEY_VERIFY_ERROR);
        }
        /**
         * 5、修改订单的支付状态
         */
        orderService.paid(orderDTO);
        return payResponse;
    }

}

同样的通知微信支付后台可能会多次发送给商户系统。所以我们在接收了微信的异步支付通知,处理自身的业务逻辑之后,需要给微信支付后台返回确认消息,这样微信就不会再重复发送同一个订单的支付结果。

因此在controller中,我们返回了一个ModelAndView,对应的视图为src\main\resources\templates\pay\success.ftl,文件内容如下

<xml>
    <return_code><![CDATA[SUCCESS]]></return_code>
    <return_msg><![CDATA[OK]]></return_msg>
</xml>

 

### 实现C#应用向微信公众号发送推送通知 为了通过C#应用程序实现向微信公众号发送推送通知,需遵循特定流程来配置并调用相应的API接口。首先,要获得用于访问微信公众平台API的`access_token`,这是所有API请求的关键凭证。 #### 获取Access Token 全局唯一的`access_token`可以通过HTTP GET方法从官方服务器获取。具体来说,应构建如下URL并向其发起GET请求: ```plaintext https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET[^1] ``` 其中`APPID`和`APPSECRET`代表开发者账号下的小程序或服务号的身份标识符及其密钥。成功响应会返回JSON格式的数据包,内含所需的`access_token`字符串及过期时间戳。 #### 发送模板消息 一旦拥有了有效的`access_token`,就可以准备发送模板消息了。这一步骤涉及设置好接收者openid、模板ID以及其他必要的字段信息。以下是利用HttpClient库编写的简单示例代码片段展示如何执行此操作: ```csharp using System; using System.Net.Http; using Newtonsoft.Json.Linq; public class WeChatPushNotificationService { private static readonly string AccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token"; private static readonly string SendMessageUrlFormat = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}"; public async Task SendTemplateMessageAsync(string appId, string appSecret, JObject messageData) { using (var client = new HttpClient()) { // Step 1: Get access token. var accessTokenResponse = await client.GetStringAsync($"{AccessTokenUrl}?grant_type=client_credential&appid={appId}&secret={appSecret}"); dynamic jsonResult = JObject.Parse(accessTokenResponse); string accessToken = jsonResult.access_token; // Step 2: Post template message with the obtained access token. var sendMessageUrl = String.Format(SendMessageUrlFormat, accessToken); HttpResponseMessage response = await client.PostAsync(sendMessageUrl, new StringContent(messageData.ToString(), Encoding.UTF8, "application/json")); if (!response.IsSuccessStatusCode) { throw new Exception($"Failed to send wechat push notification. Status code {response.StatusCode}, Reason phrase &#39;{response.ReasonPhrase}&#39;."); } } } } ``` 上述代码展示了怎样创建一个异步函数`SendTemplateMessageAsync()`,它接受三个参数:`appId`, `appSecret` 和待发送的消息体(作为JObject对象传递),并通过两次网络请求完成整个过程——先是取得临时令牌,接着使用该令牌提交实际的通知内容给定的目标用户。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值