Springboot对接支付宝详细实例以及沙箱跳转报错502 Bad Gateway问题原因

注意:沙箱网关地址和生产环境网关地址不一致,如果是沙箱环境需要配置沙箱网关地址

前言

沙箱环境问题

使用的sdk版本比较新的话(这版本多新才算新啊?我也不知道),很大可能不是你的问题,而是沙箱环境自身的问题,有条件的话建议在生产环境做测试,没条件就听天由命吧…

官方文档对于该问题的描述

在这里插入图片描述

我这里使用的版本:

            <!-- 支付宝 -->
            <dependency>
                <groupId>com.alipay.sdk</groupId>
                <artifactId>alipay-sdk-java</artifactId>
                <version>4.40.82.ALL</version>
            </dependency>

解决方式

把沙箱配置改成生产环境的配置

支付宝对接

注入AlipayConfig

package com.explain.framework.config;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author QiuXin
 * @since 2025/3/19
 */
@Configuration
@ConfigurationProperties(prefix = "alipay")
public class TestAliPayConfig extends AlipayConfig {

    @Bean
    public AlipayClient alipayClient() throws AlipayApiException {
        return new DefaultAlipayClient(getAlipayConfig(1));
    }

    /**
     * 通过不同方式获取支付宝支付配置
     *
     * @param configurationMode 配置模式:1-密钥加签;2-服务器证书地址加签;<s>3-证书内容加签(证书内容过多已废弃)</s>
     * @return {@link AlipayConfig}
     */
    public AlipayConfig getAlipayConfig(int configurationMode) {
        AlipayConfig alipayConfig = new AlipayConfig();
        if (configurationMode == 1) {
            alipayConfig.setAppId(super.getAppId());
            alipayConfig.setPrivateKey(super.getPrivateKey());
            alipayConfig.setAlipayPublicKey(super.getAlipayPublicKey());
        } else {
            alipayConfig.setAppId(super.getAppId());
            alipayConfig.setPrivateKey(super.getPrivateKey());
            alipayConfig.setAppCertPath(super.getAppCertPath());
            alipayConfig.setAlipayPublicCertPath(super.getAlipayPublicCertPath());
            alipayConfig.setRootCertPath(super.getRootCertPath());
        }
        return alipayConfig;
    }
}

配置文件

#支付宝
alipay:
  #应用id
  appId: 
  #应用私钥(需要使用支付宝开放平台密钥工具的格式转换功能转换为PKCS8格式,不然可能报错私钥格式不对)
  private-key: 
  #支付宝公钥
  alipay-publicKey: 
  #证书文件地址加签
#  app-cert-path: C:\Users\xxx(你的服务器或本地路径)\appCertPublicKey_2021005130641045.crt
#  alipay-public-cert-path: C:\Users\xxx(你的服务器或本地路径)\alipayCertPublicKey_RSA2.crt
#  root-cert-path: C:\Users\xxx(你的服务器或本地路径)\alipayRootCert.crt

后端使用

package com.explain.framework.alipay.service.impl;

import cn.hutool.json.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.domain.RefundGoodsDetail;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.explain.framework.alipay.service.AliPayService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.alipay.api.AlipayConstants.CHARSET;
import static com.alipay.api.AlipayConstants.SIGN_TYPE_RSA2;

/**
 * @author QiuXin
 * @since 2025/3/19
 */
@Slf4j
@Service
public class AliPayServiceImpl implements AliPayService {

    @Resource
    private AlipayClient alipayClient;

    @Resource
    private AlipayConfig alipayConfig;

    @Override
    public void tradePagePay(HttpServletResponse response) {
        log.info("收到支付宝下单请求");
        // 发送请求的 Request类
        AlipayTradePagePayRequest request = getAlipayTradePagePayRequest();
        // 执行请求,拿到响应的结果,返回给浏览器
        String form = "";
        try {
            // 调用SDK生成表单
            form = alipayClient.pageExecute(request).getBody();
            log.info("下单form信息:{}", form);
        } catch (AlipayApiException e) {
            log.error("支付宝下单失败:{}", e.getMessage());
        }
        response.setContentType("text/html;charset=utf-8");
        try {
            // 直接将完整的表单html输出到页面
            response.getWriter().write(form);
            response.getWriter().flush();
            response.getWriter().close();
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

    @NotNull
    private static AlipayTradePagePayRequest getAlipayTradePagePayRequest() {
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        // 支付宝异步回调地址
        // 注意:需要关闭此接口的权限校验或放行网关白名单等一切可能导致请求被拦截、或无法访问的处理
        // 并且需要运行在公网可以访问的地方,如果没有就需要一个内网穿透工具,推荐一个可以免费使用的:https://i.cpolar.com/m/5qAl
        request.setNotifyUrl("https://5860f010.r31.cpolar.top/alipay/notify");
        JSONObject bizContent = new JSONObject();
        // 我们自己生成的订单编号
        bizContent.set("out_trade_no", "777777");
        // 订单的总金额
        bizContent.set("total_amount", 0.01);
        // 支付的名称
        bizContent.set("subject", "水果16");
        // 固定配置
        bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY");
        request.setBizContent(bizContent.toString());
        return request;
    }

    @Override
    public void alipayNotify(HttpServletRequest request, HttpServletResponse response) {
        // 获取消息内容
        Map<String, String> params = getParams(request);
        // params参数示例
//        String gmtCreate = "2025-03-20 15:27:07";
//        String charset = "utf-8";
//        String gmtPayment = "2025-03-20 15:27:11";
//        String notifyTime = "2025-03-20 15:27:12";
//        String subject = "??16";
//        String sign = "oIguKFbITbx5McZELQksdsadsaWKQjxedDSADSADSADHY8NLmIBwkn/ASDsadsadsadsadsdsa0pf5frnfazDk3SP89Rxd3NeXSY/pnFYCEK7SH/5pby+tHTBPXV4tds5a45d6saGY9qmnVnWGxBcyOJmMLoQnFzBQAChwanD87IWSiJJf3uPuqTaMhJW4Yrb3837G9AGlkTdroTDc9KgY1+wi4XD2tz1f3IGkaFvKyUBN2WPtCGTRL3NVRiVIzaRTlG7Ojh2zTaVsuAly06xOO+rRCXkYP6VS9dq2iw18XCqsapdospa23==";
//        String merchantAppId = "123123123";
//        String buyerOpenId = "0d32s1a2ds1a2d12sa3-dsads-ds1a2d1sa2d12";
//        String invoiceAmount = "0.01";
//        String version = "1.0";
//        String notifyId = "d12s3a1d2s3a1d23sa12d3sa";
//        String fundBillList = "[{\"amount\":\"0.01\",\"fundChannel\":\"ALIPAYACCOUNT\"}]";
//        String notifyType = "trade_status_sync";
//        String outTradeNo = "777777";
//        String totalAmount = "0.01";
//        // 交易状态
//        String tradeStatus = "TRADE_SUCCESS";
//        // 支付宝生成的订单号
//        String tradeNo = "2025111111111111111111";
//        String authAppId = "";
//        String receiptAmount = "0.01";
//        String pointAmount = "0.00";
//        String buyerPayAmount = "0.01";
//        String appId = "123123123123153153";
//        String signType = "RSA2";
//        String sellerId = "265256156156";

        //验签
        boolean signResult = false;
        try {
            signResult = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), CHARSET, SIGN_TYPE_RSA);
        } catch (AlipayApiException e) {
            log.error("支付宝异步通知消息验签异常:{}", e.getMessage());
        }
        if (signResult) {
            log.info("收到支付宝发送的支付结果通知");
            String outTradeNo = request.getParameter("out_trade_no");
            log.info("交易流水号:{}", outTradeNo);
            //交易状态
            String tradeStatus = new String(request.getParameter("tradeStatus").getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            //交易成功
            switch (tradeStatus) {
                case "TRADE_SUCCESS":
                    //支付成功的业务逻辑,比如落库,开vip权限等
                    log.info("订单:{} 交易成功", outTradeNo);
                    break;
                case "TRADE_FINISHED":
                    log.info("交易结束,不可退款");
                    //其余业务逻辑
                    break;
                case "TRADE_CLOSED":
                    log.info("超时未支付,交易已关闭,或支付完成后全额退款");
                    //其余业务逻辑
                    break;
                case "WAIT_BUYER_PAY":
                    log.info("交易创建,等待买家付款");
                    //其余业务逻辑
                    break;
                default:
                    break;
            }
            try {
                //返回success给支付宝,表示消息我已收到,不用重调
                response.getWriter().write("success");
            } catch (IOException e) {
                log.error(e.getMessage());
            }
        } else {
            //返回fail给支付宝,表示消息我没收到,请重试
            try {
                response.getWriter().write("fail");
            } catch (IOException e) {
                log.error("支付宝异步通知消息返回fail给支付宝异常:{}", e.getMessage());
            }
        }
    }

    @Override
    public String tradeRefund(HttpServletRequest request) {
        log.info("收到支付宝订单退款请求");
        // 构造请求参数以调用接口
        AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();

        // 设置商户订单号
        model.setOutTradeNo("777777");

        // 设置支付宝交易号
        model.setTradeNo("2025032022001430951415807279");

        // 设置退款金额
        model.setRefundAmount("0.01");

        // 设置退款原因说明
        model.setRefundReason("正常退款");

        // 设置退款请求号
        model.setOutRequestNo("777777");

        // 设置退款包含的商品列表信息
        List<RefundGoodsDetail> refundGoodsDetail = new ArrayList<>();
        RefundGoodsDetail refundGoodsDetail0 = new RefundGoodsDetail();
        refundGoodsDetail0.setOutSkuId("outSku_01");
        refundGoodsDetail0.setOutItemId("outItem_01");
        refundGoodsDetail0.setGoodsId("apple-01");
        refundGoodsDetail0.setRefundAmount("19.50");
        List<String> outCertificateNoList = new ArrayList<>();
        outCertificateNoList.add("202407013232143241231243243423");
        refundGoodsDetail0.setOutCertificateNoList(outCertificateNoList);
        refundGoodsDetail.add(refundGoodsDetail0);
        model.setRefundGoodsDetail(refundGoodsDetail);

        // 设置查询选项
        List<String> queryOptions = new ArrayList<>();
        queryOptions.add("refund_detail_item_list");
        model.setQueryOptions(queryOptions);

        alipayRequest.setBizModel(model);
        try {
            String responseBody = alipayClient.execute(alipayRequest).getBody();
            log.info("退款信息:{}", responseBody);
        } catch (AlipayApiException e) {
            log.error("退款失败,原因:{}", e.getMessage());
            return "退款失败,原因:" + e.getMessage();
        }
        return "退款成功";
    }

    @NotNull
    private static Map<String, String> getParams(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>(0);
        //获取支付宝POST过来反馈信息,将异步通知中收到的待验证所有参数都存放到map中
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            String[] values = entry.getValue();
            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(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
            params.put(entry.getKey(), valueStr);
        }
        return params;
    }
}

其他有用的参考文档:
保姆级教程:SpringBoot 对接支付宝完成扫码支付,完整流程梳理!

502 Bad Gateway错误通常发生在后端服务器尝试从上游服务器(如API服务)接收数据时,但由于上游服务器暂时无法处理请求,导致返回这个错误。在Java中处理支付宝沙箱环境的502错误,可能涉及以下几个步骤: 1. **检查网络连接**:确保你的应用能够正常访问支付宝沙箱环境,包括API的URL是否正确,网络防火墙和代理设置是否允许访问。 2. **检查API服务**:登录支付宝开放平台,检查沙箱环境是否正常,有时可能是支付宝端的问题,比如服务临时维护或配置更改。 3. **代码问题**:检查你的代码中调用支付宝API的部分,确保请求头、参数正确无误,并且超时设置合理。使用try-catch捕获异常,记录详细的错误日志。 4. **服务器配置**:如果使用的是反向代理(如Nginx或Apache),检查其配置,确保配置了正确的错误处理和重试策略。 5. **限流或并发控制**:有可能是并发请求过多,导致服务器负载过高。考虑增加请求的重试机制,或者使用限流算法避免短时间内发送过多请求。 6. **服务器性能优化**:提升服务器的处理能力,例如增加内存、调整线程池大小等,以更好地应对高并发请求。 7. **排查代码逻辑**:检查是否有代码逻辑错误,比如循环调用API,或者无限递归导致服务器资源耗尽。 如果你遇到了这个问题,相关问题可能包括:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值