stripe国际支付(对接支付宝、微信)

Stripe API支付(java)多方支付 Stripe支付服务端(java),Stripe checkout, Stripe,多方支付,Stripe创建账户,Stripe CLI本地调式 阅读详情
AI摘要

本文档介绍了如何在Spring框架下对接Stripe国际支付,重点是支付宝和微信支付的集成。由于Stripe官方Java demo使用Spark框架,文中详细说明了在Spring中进行手动验签的过程,并提供了回调地址配置、接口调用示例以及遇到的问题和解决方法,包括Stripe回调的72小时递增回调机制。

前言:stripe国际支付现在网上资料很少,且不支持中国,所以如果要用需要去支持的国家注册商户,官网的java demo是用的spark框架,我这里用的spring,验签需要手动验签,且不能用官网的方法

正文:

支付宝文档地址:https://stripe.com/docs/sources/alipay

微信支付文档地址:https://stripe.com/docs/sources/wechat-pay

支付宝和微信的流程差不多一样。

做了个简单的时序图

关于配置:

回调地址配置,可以每个触发事件都配置不一样的url,也可以都配置一个,我只配置了一个

获得source时候发送请求用到的公匙:

代码:

<!-- stripe支付官方包 -->
<dependency>
    <groupId>com.stripe</groupId>
    <artifactId>stripe-java</artifactId>
    <version>7.26.0</version>
</dependency>

其实只有三个接口:

1.给前端准备数据

2.授权完回调地址

3.回调接口

回调接口:

常量类:

service:

package com.otcbi.pay.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.gson.JsonSyntaxException;
import com.otcbi.coin.common.exception.ApiException;
import com.otcbi.coin.common.exception.ApiResponMessage;
import com.otcbi.constat.Consts;
import com.otcbi.pay.entity.StripeOrder;
import com.otcbi.pay.service.IGoodsOnlineService;
import com.otcbi.pay.service.IStripeOrderService;
import com.otcbi.pay.service.IStripeWebhookMessageService;
import com.otcbi.shop.dto.StripeCreateSourceDTO;
import com.otcbi.shop.entity.Orders;
import com.otcbi.shop.service.IOrdersService;
import com.stripe.Stripe;
import com.stripe.exception.SignatureVerificationException;
import com.stripe.model.Charge;
import com.stripe.model.Event;
import com.stripe.model.EventData;
import com.stripe.net.Webhook;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@Service
public class IGoodsOnlineServiceImpl implements IGoodsOnlineService {

    private static final Logger logger = LoggerFactory.getLogger(IGoodsOnlineServiceImpl.class);

    @Value("${stripe.homeUrl}")
    private String homeUrl;

    @Value("${stripe.apiKey}")
    String stripeApiKey;

    @Value("${stripe.webhookSecret}")
    String stripeWebhookSecret;


    @Autowired
    private IOrdersService iOrdersService;

    @Autowired
    private IStripeOrderService iStripeOrderService;

    @Autowired
    private IStripeWebhookMessageService iStripeWebhookMessageService;

    public StripeCreateSourceDTO createSource(Long ordersId) throws Exception {
        Orders orders = iOrdersService.getById(ordersId);
        if (orders == null) {
            throw new ApiException(ApiResponMessage.SHOP_ORDERS_EXIST, null);
        } else if (orders.getPayState() == 2) {
            throw new ApiException(ApiResponMessage.ORDERS_ALREADY_FINISHED, null);
        }
        StripeCreateSourceDTO source = new StripeCreateSourceDTO();
        source.setUserId(orders.getUserId());

        if (orders.getPayType() == 1) {
            source.setType("alipay");
        } else if (orders.getPayType() == 2) {
            source.setType("wechat");
        }
        source.setCurrency(orders.getCoin());
        source.setOrderNum(orders.getOrderNum());
        source.setReturnUrl(homeUrl + "/stripe/createSourceRetuenBack?orderNum=" + orders.getOrderNum());

        QueryWrapper<StripeOrder> wrapper = new QueryWrapper<>();
        wrapper.eq("is_deleted", "N");
        wrapper.eq("order_num", orders.getOrderNum());
        wrapper.eq("is_cancel", 0);
        StripeOrder stripeOrder = iStripeOrderService.getOne(wrapper);

        if (stripeOrder == null) {
            //创建stripe订单
            stripeOrder = new StripeOrder();
            stripeOrder.setIsDeleted("N");
            stripeOrder.setCreateTime(LocalDateTime.now());
            stripeOrder.setOrderNum(orders.getOrderNum());
            stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_PENDING);
            Integer realAmount = Integer.valueOf(new BigDecimal(orders.getActualPrice().toString()).multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_DOWN).toString());
            Integer amount = Integer.valueOf(realAmount.toString());
            source.setAmount(amount);
            stripeOrder.setAmount(realAmount);
            stripeOrder.setType(source.getType());
            stripeOrder.setUserId(orders.getUserId());
            stripeOrder.setCurrency(orders.getCoin());
            iStripeOrderService.save(stripeOrder);
            return source;
        } else {
            String status = stripeOrder.getStatus();

            if (Consts.PAY_STRIPE_STATUS_SUCCEEDED.equals(status)) {
                //已经完成
                throw new ApiException(ApiResponMessage.ORDERS_ALREADY_FINISHED, null);
            } else if (Consts.PAY_STRIPE_STATUS_CANCELED.equals(status) || Consts.PAY_STRIPE_STATUS_INSUFFICIENT_fUNDS.equals(status)
                    || Consts.PAY_STRIPE_STATUS_INVALID_AMOUNT.equals(status) || Consts.PAY_STRIPE_STATUS_CHARGE_ERROR.equals(status)) {
                //已经失效,删除原来订单,重新创建订单
                stripeOrder.setIsCancel(1);
                stripeOrder.setModifyTime(LocalDateTime.now());
                iStripeOrderService.updateById(stripeOrder);

                StripeOrder stripeOrderNew = new StripeOrder();
                stripeOrderNew.setIsDeleted("N");
                stripeOrderNew.setCreateTime(LocalDateTime.now());
                stripeOrderNew.setOrderNum(orders.getOrderNum());
                stripeOrderNew.setStatus(Consts.PAY_STRIPE_STATUS_PENDING);
                Integer realAmount = Integer.valueOf(new BigDecimal(orders.getActualPrice().toString()).multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_DOWN).toString());
                Integer amount = Integer.valueOf(realAmount.toString());
                source.setAmount(amount);
                stripeOrderNew.setAmount(realAmount);
                stripeOrderNew.setType(source.getType());
                stripeOrder.setUserId(orders.getUserId());
                stripeOrder.setCurrency(orders.getCoin());
                iStripeOrderService.save(stripeOrderNew);
                return source;
            } else {
                if (Consts.PAY_STRIPE_STATUS_PENDING.equals(status)) {
                    //还未授权
                    Integer amount = Integer.valueOf(new BigDecimal(stripeOrder.getAmount().toString()).setScale(0, BigDecimal.ROUND_DOWN).toString());
                    source.setAmount(amount);
                    return source;
                } else if (Consts.PAY_STRIPE_STATUS_CHARGEABLE.equals(status)) {
                    //已经授权,按理来说这个时候已经完成了订单
                    throw new ApiException(ApiResponMessage.SHOP_ORDERS_PLAYING_ERROR, null);
                } else if (Consts.PAY_STRIPE_STATUS_FAILED.equals(status)) {
                    //拒绝授权支付,重新要求授权
                    Integer amount = Integer.valueOf(new BigDecimal(stripeOrder.getAmount().toString()).setScale(0, BigDecimal.ROUND_DOWN).toString());
                    source.setAmount(amount);
                    return source;
                } else {
                    throw new ApiException(ApiResponMessage.SHOP_GOODS_WEIXIN_PAY_ERROR, null);
                }
            }
        }
    }

    /**
     * 如果客户的支付宝账户被非法使用,支付宝和Stripe会在内部处理此问题。在支付宝的情况下,
     * 只有当客户对所提供的商品或服务有投诉时,付款才会有争议。
     * 如果发生争议,dispute.created则会发送webhook事件,Stripe会从您的Stripe余额中扣除争议金额。
     * <p>
     * 一个chargeable单一使用支付宝源必须在6小时内变得收费chargeable。如果不是,则其状态将自动转换为canceled
     * 您的集成并收到source.canceledwebhook事件。取消收费来源后,客户的授权支付宝付款将自动退还 -
     * 不会将任何款项转入您的帐户。因此,请确保您的订单已取消,并在收到source.canceled活动时通知客户。
     * 此外,pending如果不用于授权付款,则在一小时后取消资源,确保所有资源最终从pending状态转移到canceled状态(如果不使用)。
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @Transactional
    public synchronized void stripeCallBack(HttpServletRequest request, HttpServletResponse response) throws Exception {
        logger.info("============进入webhook回调=================");
        //验签
        Event event = attestation(request, response);
        if (event == null) {
            return;
        }

        /*不验签获得数据
        Event event = ApiResource.GSON.fromJson(request.getReader(), Event.class);*/
        String message = event.toJson();
        logger.info("收到内容为:" + message);
        String stripeType = event.getType();

        //把信息记录到表
        iStripeWebhookMessageService.saveWebHootMssage(event, message, stripeType);

        if (stripeType.equals("source." + Consts.PAY_STRIPE_STATUS_CHARGEABLE)) {
            //用户授权确认
            callBackPending(event, response);
        } else if (stripeType.equals("source." + Consts.PAY_STRIPE_STATUS_FAILED)) {
            //用户拒绝授权
            callBackFailed(event, response);
        } else if (stripeType.equals("source." + Consts.PAY_STRIPE_STATUS_CANCELED)) {
            //过期
            callBackCanceled(event, response);
        } else if (stripeType.equals("charge." + Consts.PAY_STRIPE_STATUS_SUCCEEDED)) {
            //stripe收款成功通知
            callBackSuccess(event, response);
        } else if (stripeType.equals("charge.dispute." + Consts.PAY_STRIPE_STATUS_CREATED)) {
            //客户投诉退款
            callBackCreated(event, response);
        } else {
            logger.error("获得未知状态" + stripeType);
            response.setStatus(500);
            logger.info("============webhook回调结束=================");
            return;
        }
        response.setStatus(200);
        logger.info("============webhook回调结束=================");
    }

    public Event attestation(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String endpointSecret = stripeWebhookSecret;
        InputStream inputStream = request.getInputStream();
        byte[] bytes = IOUtils.toByteArray(inputStream);
        String payload = new String(bytes, "UTF-8");

        String sigHeader = request.getHeader("Stripe-Signature");
        Event event = null;
        try {
            event = Webhook.constructEvent(payload, sigHeader, endpointSecret);
            logger.info("验签成功");
            response.setStatus(200);
            return event;
        } catch (JsonSyntaxException e) {
            logger.error("验签失败");
            response.setStatus(400);
        } catch (SignatureVerificationException e) {
            logger.error("验签失败");
            e.printStackTrace();
            response.setStatus(400);
        }
        logger.info("============webhook回调结束=================");
        return null;
    }

    public void callBackPending(Event event, HttpServletResponse response) throws Exception {
        EventData eventData = event.getData();
        JSONObject json = JSONObject.parseObject(eventData.getObject().toJson());
        String client_secret = json.getString("client_secret");
        String orderNum = json.getString("statement_descriptor");
        String stripe_id = json.getString("id");
        String type = json.getString("type");
        String amount = json.getString("amount");
        String currency = json.getString("currency");
        String userId = json.getJSONObject("owner").getString("name");

        QueryWrapper<StripeOrder> wrapper = new QueryWrapper<>();
        wrapper.eq("is_deleted", "N");
        wrapper.eq("order_num", orderNum);
        wrapper.eq("is_cancel", 0);
        wrapper.eq("type", type);
        wrapper.eq("user_id", userId);
        StripeOrder stripeOrder = iStripeOrderService.getOne(wrapper);
        if (stripeOrder == null) {
            //订单不存在
            logger.error("Stripe收到不存在的订单回调" + orderNum);
            response.setStatus(500);
        } else {
            if (!stripeOrder.getStatus().equals(Consts.PAY_STRIPE_STATUS_PENDING)) {
                logger.error("Stripe收到违法订单" + orderNum);
            }
            if (!amount.equals(stripeOrder.getAmount().toString())) {
                logger.error("Stripe收到金额对不上的订单回调" + orderNum);
                response.setStatus(500);
            }
            //客户已经完成授权
            stripeOrder.setStripeId(stripe_id);
            stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_CHARGEABLE);
            stripeOrder.setClientSecret(client_secret);
            stripeOrder.setModifyTime(LocalDateTime.now());
            iStripeOrderService.updateById(stripeOrder);
            logger.info("===================" + orderNum + "订单授权成功=============");
            //创建支付订单
            try {
                createCharge(stripeOrder, Integer.valueOf(amount), currency, stripe_id, orderNum);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error(orderNum + "stripe创建收费订单失败");
            }

        }
    }

    /**
     * 拒绝授权
     *
     * @param event
     * @param response
     * @throws Exception
     */
    public void callBackFailed(Event event, HttpServletResponse response) throws Exception {
        EventData eventData = event.getData();
        JSONObject json = JSONObject.parseObject(eventData.getObject().toJson());
        String client_secret = json.getString("client_secret");
        String orderNum = json.getString("statement_descriptor");
        String stripe_id = json.getString("id");
        String type = json.getString("type");
        String amount = json.getString("amount");
        String currency = json.getString("currency");
        String userId = json.getJSONObject("owner").getString("name");

        QueryWrapper<StripeOrder> wrapper = new QueryWrapper<>();
        wrapper.eq("is_deleted", "N");
        wrapper.eq("order_num", orderNum);
        wrapper.eq("is_cancel", 0);
        wrapper.eq("type", type);
        wrapper.eq("user_id", userId);
        StripeOrder stripeOrder = iStripeOrderService.getOne(wrapper);
        if (stripeOrder == null) {
            //订单不存在
            logger.error("Stripe收到不存在的订单回调" + orderNum);
            response.setStatus(500);
        } else {
            if (!stripeOrder.getStatus().equals(Consts.PAY_STRIPE_STATUS_PENDING)) {
                logger.error("Stripe收到违法订单" + orderNum);
            }
            if (!amount.equals(stripeOrder.getAmount().toString())) {
                logger.error("Stripe收到金额对不上的订单回调" + orderNum);
                response.setStatus(500);
            }
            //客户不授权删除订单
            stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_FAILED);
            stripeOrder.setClientSecret(client_secret);
            stripeOrder.setModifyTime(LocalDateTime.now());
            stripeOrder.setIsCancel(1);
            stripeOrder.setStripeId(stripe_id);
            iStripeOrderService.updateById(stripeOrder);
            logger.info("===================" + orderNum + "订单拒绝授权处理成功=============");
        }
    }


    /**
     * 过期订单
     *
     * @param event
     * @param response
     * @throws Exception
     */
    public void callBackCanceled(Event event, HttpServletResponse response) throws Exception {
        EventData eventData = event.getData();
        JSONObject json = JSONObject.parseObject(eventData.getObject().toJson());
        String client_secret = json.getString("client_secret");
        String orderNum = json.getString("statement_descriptor");
        String stripe_id = json.getString("id");
        String type = json.getString("type");
        String amount = json.getString("amount");
        String currency = json.getString("currency");
        String userId = json.getJSONObject("owner").getString("name");

        QueryWrapper<StripeOrder> wrapper = new QueryWrapper<>();
        wrapper.eq("is_deleted", "N");
        wrapper.eq("order_num", orderNum);
        wrapper.eq("is_cancel", 0);
        wrapper.eq("type", type);
        wrapper.eq("user_id", userId);
        wrapper.eq("stripe_id", stripe_id);
        StripeOrder stripeOrder = iStripeOrderService.getOne(wrapper);
        if (stripeOrder == null) {
            //订单不存在
            logger.error("Stripe收到不存在的订单回调" + orderNum);
            response.setStatus(500);
        } else {
            if (!stripeOrder.getStatus().equals(Consts.PAY_STRIPE_STATUS_PENDING)) {
                logger.error("Stripe收到违法订单" + orderNum);
            }
            if (!amount.equals(stripeOrder.getAmount().toString())) {
                logger.error("Stripe收到金额对不上的订单回调" + orderNum);
                response.setStatus(500);
            }
            //订单过期删除订单
            stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_CANCELED);
            stripeOrder.setClientSecret(client_secret);
            stripeOrder.setModifyTime(LocalDateTime.now());
            stripeOrder.setIsCancel(1);
            iStripeOrderService.updateById(stripeOrder);
            logger.info("===================" + orderNum + "订单过期处理成功=============");
        }
    }

    public void callBackCreated(Event event, HttpServletResponse response) throws Exception {
        EventData eventData = event.getData();
        //待写
    }


    public void callBackSuccess(Event event, HttpServletResponse response) throws Exception {
        EventData eventData = event.getData();
        JSONObject json = JSONObject.parseObject(eventData.getObject().toJson());
        String orderNum = json.getJSONObject("source").getString("statement_descriptor");
        String stripe_id = json.getJSONObject("source").getString("id");
        String type = json.getJSONObject("source").getString("type");
        String amount = json.getJSONObject("source").getString("amount");
        String userId = json.getJSONObject("source").getJSONObject("owner").getString("name");
        String payId = json.getString("id");

        QueryWrapper<StripeOrder> wrapper = new QueryWrapper<>();
        wrapper.eq("is_deleted", "N");
        wrapper.eq("order_num", orderNum);
        wrapper.eq("is_cancel", 0);
        wrapper.eq("type", type);
        wrapper.eq("user_id", userId);
        wrapper.eq("stripe_id", stripe_id);
        StripeOrder stripeOrder = iStripeOrderService.getOne(wrapper);
        if (stripeOrder == null) {
            //订单不存在
            logger.error("Stripe收到不存在的订单回调" + orderNum);
            response.setStatus(500);
        } else {
            if (!stripeOrder.getStatus().equals(Consts.PAY_STRIPE_STATUS_CHARGEABLE)) {
                logger.error("Stripe收到违法订单" + orderNum);
            }
            if (!amount.equals(stripeOrder.getAmount().toString())) {
                logger.error("Stripe收到金额对不上的订单回调" + orderNum);
                response.setStatus(500);
            }
            //客户付款成功
            stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_SUCCEEDED);
            stripeOrder.setModifyTime(LocalDateTime.now());
            stripeOrder.setPayId(payId);
            iStripeOrderService.updateById(stripeOrder);
            //更改订单状态
            QueryWrapper<Orders> orderWrapper = new QueryWrapper<>();
            orderWrapper.eq("order_num", orderNum);
            orderWrapper.eq("is_deleted", "N");
            Orders orders = iOrdersService.getOne(orderWrapper);
            orders.setModifyTime(LocalDateTime.now());
            orders.setPayState(2);
            iOrdersService.updateById(orders);
            logger.info("===================" + orderNum + "订单付款成功=============");
        }
    }

    /**
     * 创建收费订单
     *
     * @param amount
     * @param currency
     * @param stripeId
     * @throws Exception 支付宝付款的费用创建可能会返回以下任何错误:
     *                   insufficient_funds    支付宝账户资金不足,无法完成购买。客户应为其帐户注资并重试,或使用其他付款方式。
     *                   invalid_amount    如果收费金额大于支付宝支持的费用,则会发生这种情况。
     */
    public void createCharge(StripeOrder stripeOrder, Integer amount, String currency, String stripeId, String orderNum) throws Exception {
        Stripe.apiKey = stripeApiKey;
        Map<String, Object> chargeParams = new HashMap<String, Object>();
        chargeParams.put("amount", amount);
        chargeParams.put("currency", currency);
        chargeParams.put("source", stripeId);
        chargeParams.put("description", orderNum + " completion of payment");

        Charge charge = Charge.create(chargeParams);
        String errorMsg = charge.getFailureMessage();
        if (StringUtils.isEmpty(errorMsg)) {
            logger.info(orderNum + "订单请求支付成功");
        } else {
            if (errorMsg.equals("insufficient_funds")) {
                logger.error(orderNum + "订单用户支付宝余额不足");
                stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_INSUFFICIENT_fUNDS);
                stripeOrder.setModifyTime(LocalDateTime.now());
            } else if (errorMsg.equals("invalid_amount")) {
                logger.error(orderNum + "订单收费金额大于支付宝支持的费用");
                stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_INVALID_AMOUNT);
                stripeOrder.setModifyTime(LocalDateTime.now());
            } else {
                logger.error(orderNum + errorMsg);
                stripeOrder.setStatus(Consts.PAY_STRIPE_STATUS_CHARGE_ERROR);
                stripeOrder.setModifyTime(LocalDateTime.now());
            }
            iStripeOrderService.updateById(stripeOrder);
        }
        logger.info("===================" + orderNum + "订单申请扣费成功=============");
    }


}

h5页面:

createSource:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <!--官方js-->
    <script src="https://js.stripe.com/v3/"></script>
    <script type="text/javascript" src="/jquery.min.js"></script>

    <script type="text/javascript">
        $(document).ready(function () {
            var amount = $("#amount").val();
            var returnUrl = $("#returnUrl").val();
            var currency = $("#currency").val();
            var type = $("#type").val();
            var userId = $("#userId").val();
            var orderNum = $("#orderNum").val();

            var stripe = Stripe($('#stripe').val());
            stripe.createSource({
                type: type,
                amount: amount,
                currency: currency,
                statement_descriptor : orderNum,
                owner: {
                    name: userId,
                },
                redirect: {
                    return_url: returnUrl
                },
            }).then(function (result) {
                // handle result.error or result.source
                if (result.source != null) {
                    if(result.source.type == "wechat"){
                        window.location.href=result.source.wechat.qr_code_url;
                    }else {
                        window.location.href=result.source.redirect.url;
                    }
                } else {
                    alert(result.error.message);
                }
            });
        });
    </script>
</head>

</head>
<body>
<h1>跳转授权页面中。。。。</h1>
<input type="hidden" id="stripe" th:value="${stripe}">
<input type="hidden"  id="type" th:value="${dto.type}">
<input type="hidden"  id="amount" th:value="${dto.amount}">
<input type="hidden"  id="returnUrl" th:value="${dto.returnUrl}">
<input type="hidden"  id="currency" th:value="${dto.currency}">
<input type="hidden"  id="userId" th:value="${dto.userId}">
<input type="hidden"  id="orderNum" th:value="${dto.orderNum}">
</body>
</html>

temp.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="/jquery.min.js"></script>
</head>
<body>
        <h1>您的订单授权已受理,正在等待第三方处理,请稍后查询订单状态</h1>
</body>
</html>

 

这里遇到一个特别坑的地方:就是验签的时候官网给的demo是:

用到spark,以为引入spark pom就行了,结果一直不行,后来联系他们客服,然后给了我个irc的地址让我跟他们技术人员谈,聊了好久才知道,原来他们用的是spark框架不能和spring拼凑使用,聊天内容:

聊天知道了几个重要内容:

如果不响应会持续回调72小时,时间递增的回调

验签获取payload 的获取关键代码:

InputStream inputStream = request.getInputStream();
byte[] bytes = IOUtils.toByteArray(inputStream);
String payload = new String(bytes, "UTF-8");

如果有什么不懂欢迎留言!

 

Stripe支付集成:从零开始的开发指南 Stripe是一家全球性的支付处理平台,为在线企业和开发者提供简便、安全、可扩展的支付解决方案。其灵活性和强大的API使得从小型创业公司到大型企业都能够轻松地集成支付功能。Stripe的使命是简化互联网交易,为商家提供无缝、创新且高效的支付工具。为了提供一致的用户体验,您可以自定义Stripe Checkout页面的外观,使其与您的应用风格相匹配,用户将感到更加信任和舒适。自定义主题: 使用style参数可以自定义Stripe Checkout页面的颜色、字体等外观。// ... 阅读详情

相关推荐

Android接入stripe支付

Android接入stripe支付 阅读之前请大家先了解流程哦(适用于先绑卡后扣款的情况) stripe国际化支付流程: 1.初始化stripe,创建stripe对象; 2.检索后台SetupIntent,得到client secret,也就是client token;(客户机密可用于通过信用卡网络验证和验证卡详细信息) 3.获取卡片信息,判断卡号,有效期,cvv是否正确有效 4.客户端收集付款方...

jyxlichao的博客 3001

stripe支付集成

stripe

qq_55756037的博客 4975

PHP+UniApp跨端分销商城系统开发实战

跨端开发技术通过一套代码实现多平台适配,大幅降低开发成本。基于PHP的Laravel框架与UniApp的组合,可以构建高性能的分布式系统架构,特别适合电商类应用。这种技术方案通过前后端分离设计和JSON字段优化,解决了多语言商城的数据存储与查询性能问题。在实际应用中,采用闭包表模型实现O(1)时间复杂度的分销关系查询,结合分区表设计处理海量支付日志。对于需要快速拓展海外市场的企业,这种支持微信小程序、APP、H5三端兼容的解决方案,配合多级分佣算法和国际支付对接,能有效提升分销业务占比。数据显示,成熟案例中

weixin_35370061的博客 119

C#接入Stripe,实现支付宝微信支付

C#接入Stripe,实现支付宝微信支付。

让梦想疯狂 1796

WooCommerce独立站从零到上线:腾讯云轻量服务器+WordPress全流程避坑指南

本文详细介绍了如何利用腾讯云轻量服务器快速搭建WooCommerce独立站的全流程,涵盖服务器选购、WordPress初始化、支付网关对接及国内ICP备案等关键步骤。特别针对跨境电商创业者,提供了部署安装的实用技巧和避坑指南,帮助非技术背景用户30分钟内完成电商站点上线。

weixin_29276847的博客 489

Stripe开发使用指南--国际支付(含支付宝)

前段时间,因为Jason让我帮忙把Stripe支付集成到他个人网站上去,让我有机会接触到支付系统开发,同时也因为苦于没有找到太多中文方面相关文档介绍,所以做个总结,也方便以后有需要的同学。 关于Stripe支付 第一次听说Stripe还是在几个月前的一个新闻上了解到,大致说的是美国总统都在使用它,极有可能成功下一个Paypal。这么受欢迎的一个支付平台到底有什么好处呢?我粗略搜集了一下: 一条...

weixin_34248023的博客 7934

2021-01-06

国外stripe支付,超简单几行代码搞定 qq_38259132的博客 06-19 6450 公司在做海外的项目 需要stripe支付 很简单 几行代码 先加入依赖:compile 'com.stripe:stripe-android:6.1.2'总...

weixin_46315812的博客 544

Java整合Stripe支付

Java整合Stripe支付

AiFlutter的博客 2106

代购业务金流解决方案:推荐支付方式及对接材料详解

选择合适的支付方式并准备好相应的申请材料,是建立稳定、安全支付渠道的关键第一步。建议代购从业者根据自身业务特点,选择2-3种支付方式组合使用,既能满足不同客户需求,也能分散支付风险。本文将为您介绍几种适合代购业务对接的支付方式,并详细说明每种支付方式所需的对接材料,帮助您解决代购业务中的金流难题。A:从几天到几周不等,取决于支付平台的审核流程和您提供材料的完整性。A:部分支付平台支持个人申请,但企业账户通常有更高限额和更多功能。A:可谈判交易费率,或选择对您业务量有优惠政策的支付平台。

zzqssliu的博客 863

告别Link180!在Ansys Mechanical 2020R2中正确启用Cable280绳索单元(附Beta选项开启指南)

本文详细介绍了在Ansys Mechanical 2020R2中启用Cable280绳索单元的全过程,包括Beta选项的开启步骤、建模技巧及高阶应用。Cable280作为专为绳索仿真设计的单元,相比传统的Link180单元,在大变形模拟和计算效率上表现更优,特别适合斜拉桥、电梯牵引绳等工程场景。

weixin_33711647的博客 405

【新手必看】蓝牙的HOGP和HID、GATT有什么区别和联系

让新手宏观了解蓝牙HOGP、HID、GATT这三个协议的区别和联系

qq_51976334的博客 1565

Stripe国际支付简介及API对接

关于Stripe 最近公司正在做一个海外APP,涉及到海外支付,经过几番调研,选择了Stripe支付。 货币兑换:Stripe支持处理135+个货币兑换成客户当地的货币。 Stripe官网 Stripe API 注册的时候,因为不支持中国(这点很伤心啊),所以需要选择要用支持的国家注册商户,而你恰恰有这个国家的公司信息、银行卡信息之类的。绑定银行卡信息之类的,最后一定要发送手机号码验证,要不然在调...

宋先森的博客 3万+

探针卡技术演进:从金线微针到MEMS探针的Wafer Sort革命

本文探讨了探针卡技术从传统金线微针到MEMS探针的演进,及其对晶圆测试(Wafer Sort)的革命性影响。随着芯片焊垫间距进入45微米以下,MEMS技术凭借其超高精度、超长寿命和卓越的信号完整性,成为应对高密度、高速及3D IC测试挑战的关键,显著提升了测试效率与稳定性。

lstm7chronicler的博客 365

iOS接入国际支付Stripe和Braintree

黑客技术点击右侧关注,了解黑客的世界!Java开发进阶点击右侧关注,掌握进阶之路!Linux编程点击右侧关注,免费入门到精通!前言最近在开发国际版APP时需要用到支付,由...

iOS_开发 1947

初识数据结构之入门必懂——线性表(顺序表)

本文将介绍数据结构中的线性表与线性表中最简单的结构——顺序表

m0_64705485的博客 904

基于555定时器的呼吸灯电路

呼吸灯是指LED灯在芯片的控制下完成由亮到暗的逐渐变化,感觉就像人在呼吸,其广泛使用在手机上,起到一个通知提醒的作用。呼吸灯在许多灯光装饰上也有大量使用,如音响、汽车广告牌等,在生活中较为常见。...

qq1074237849的博客 9492

Stripe支付,国外支付Stripe、跨境支付

国内支付:微信、支付都集成过了 磨刀项目支持Stripe,国内账号也可以付款,我的建设银行信用卡可以付款

dazer的专栏 1万+

【GlobalMapper精品教程】074:从Lidar点云创建3D地形模型

本文基于地形点云数据,基于泊松方法、贪婪三角形测量方法和阿尔法形状创建3d地形模型。

智慧空间实验室 2167

国际支付 Superpay、Paypal、Braintree、Stripe

2019年做了个海外的商城项目,年底接触到国际支付,分别接触到的是 Superpay、Paypal、Braintree、Stripe,说下我的认识、与后台交互的大致流程: Superpay 是将微信、支付宝支付 国际化,将人民币转换成外币。支付流程和微信支付宝差不多的: 1、前端向后台下单拿到 orderid; 2、前端选择Superpay支付渠道(微信或支付宝) 将 orderid 和支付...

Ashimar_ZHZ的博客 4237

YOLOv8 眼底病变检测(眼底照片)详细说明

本文介绍了基于YOLOv8的眼底病变自动检测系统。该系统可识别糖尿病视网膜病变、青光眼等5类常见眼底病变,包括微动脉瘤、出血点等特征。核心技术包含图像预处理、模型训练、病变检测与量化分析三个模块,采用1024×1024高分辨率输入,针对医学图像特点优化数据增强策略。系统支持批量处理、可视化标注和临床报告生成,提供病变数量、面积密度和严重程度评分等量化指标。特别强调医学合规性要求,需专业医生参与数据标注和模型验证,符合医疗器械认证标准。该系统可作为眼科医生的辅助诊断工具,提高眼底病变筛查效率。

u010117029的博客 133

qcc304x笔记之手机端显示电量(九)

默认的sdk有些安卓手机不支持电量显示,所以需要加电量显示的补丁 流程分析 1. 首先新建一个task,并将task注册给电池模块 appBatteryRegister(batteryRegistrationForm) 实现handler处理函数,当battery模块电池电量更新后,会将电池百分比值发送到本模块,然后我们就可以在handler中将实时电量同步到手机端了。 hfpAtCmdInit atCmdTask.task.handler = appAtCmdHandleM...

在云巅的博客 2199

国际化支付:使用Stripe.js支持多种货币和支付方式的完整指南

在全球化的电子商务时代,为不同国家和地区的客户提供本地化的支付体验至关重要。Stripe.js作为Stripe的官方JavaScript库,为开发者提供了强大的国际化支付解决方案,支持超过135种货币和50多种本地支付方式。本文将为您详细介绍如何利用Stripe.js构建支持多种货币和支付方式的国际化支付系统。 ## 为什么选择Stripe.js进行国际化支付? Stripe.js是一个专门为

gitblog_01353的博客 481

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

初步认识 Stripe 支付

前言 这段时间在做支付相关的工作,由于业务主要是面向国外的用户,因而就接触了部分国外的支付支付相关的平台。接下来的内容主要是初步看了 Stripe 平台的文档所了解到的基本内容,后面会在使用的过程中不断地进行完善。 基本介绍和与其他支付平台的对比 什么是Stripe Stripe - 基于API的便捷支付渠道 中对Stripe所提供的功能/产品给了较为不错的参考。 使用范围 在我写这篇博客之时(2...

DoneSpeak的博客 9020

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Stripe支付介绍在asp.net mvc中开发对接,图文加代码说明

最近一个国外的电商项目,需要对接支付功能,国内的支付一般使用微信支付、支付宝、银联等等,但国际上一般使用Paypal、Skrill、BrainTree、Stripe等,经过内部综合考量所以最后选择使用 Stripe支付。 Stripe的对接相对还是比较简单的,只是相关的文档是英文的,且国内和国外的思想不一样,看文档不是很方便。 做为技术人员这里我将对接中所遇到的问题和解决方法汇总,希望能对开发人员有所帮助。 一:Stripe支付介绍 Stripe支付国际支付还是非常有名气的,具体的介...

经历过大厂、小厂风风雨雨的程序佬 1895
上一篇: 支付宝APP支付
下一篇: 线程学习1:ThreadLocal的使用
JavaMrSun
博客等级 码龄9年 27粉丝 64原创
评论 12
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值