收藏
回答

使用微信支付SDK时发送请求提示不支持今境外支付这是为什么?

package com.sky.Utils;

import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.*;
import com.wechat.pay.java.core.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ThreadLocalRandom;

@Slf4j
@Component
public class QuickStartUtil {

    // 配置参数(需替换为实际值)
    private static final String MERCHANT_ID = "";
    private static final String PRIVATE_KEY_PATH = "";
    private static final String MERCHANT_SERIAL_NUMBER = "";
    private static final String API_V3_KEY = ""; // 必须32字符
    private static final String APP_ID = "";
    private static final String NOTIFY_URL = "";
    private static final String CURRENCY = "USD";
    private static final int MAX_OUT_TRADE_NO_LENGTH = 32;

    // 跨境支付专用参数
    private static final String TRADE_TYPE = "NATIVE";
    private static final String MERCHANT_CATEGORY_CODE = "5311"; // 一般商品零售

    private PrivateKey loadPrivateKey() throws IOException {
        try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("apiclient_key.pem")) {
            if (inputStream != null) {
                return PemUtil.loadPrivateKeyFromString(new String(inputStream.readAllBytes(), StandardCharsets.UTF_8));
            }
            return PemUtil.loadPrivateKeyFromPath(PRIVATE_KEY_PATH);
        }
    }

    private Config createWechatPayConfig() {
        try {
            return new RSAAutoCertificateConfig.Builder()
                    .merchantId(MERCHANT_ID)
                    .privateKey(loadPrivateKey())
                    .merchantSerialNumber(MERCHANT_SERIAL_NUMBER)
                    .apiV3Key(API_V3_KEY)
                    .build();
        } catch (IOException e) {
            throw new RuntimeException("加载证书失败", e);
        }
    }

    private String generateOutTradeNo(String prefix) {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        String randomStr = String.valueOf(ThreadLocalRandom.current().nextInt(10000));

        String baseNo = prefix + "_" + timestamp + "_" + randomStr;
        return baseNo.length() <= MAX_OUT_TRADE_NO_LENGTH
                ? baseNo
                : baseNo.substring(0, MAX_OUT_TRADE_NO_LENGTH);
    }

    /**
     * 创建跨境支付订单(100%兼容最新SDK版本)
     */
    public String createCrossBorderPayment(Integer total, String title, String clientIp) {
        try {
            NativePayService service = new NativePayService.Builder()
                    .config(createWechatPayConfig())
                    .build();

            String outTradeNo = generateOutTradeNo("GLOBAL");
            log.info("跨境支付请求 - 订单号: {}, 金额: {} {}", outTradeNo, total, CURRENCY);

            // 1. 构建基础请求
            PrepayRequest request = new PrepayRequest();

            // 2. 设置金额
            Amount amount = new Amount();
            amount.setTotal(total);
            amount.setCurrency(CURRENCY);
            request.setAmount(amount);

            // 3. 设置基础参数
            request.setAppid(APP_ID);
            request.setMchid(MERCHANT_ID);
            request.setDescription(title.length() > 128 ? title.substring(0, 128) : title);
            request.setNotifyUrl(NOTIFY_URL);
            request.setOutTradeNo(outTradeNo);

            // 4. 设置支付场景
            SceneInfo sceneInfo = new SceneInfo();
            sceneInfo.setPayerClientIp(clientIp);
            sceneInfo.setDeviceId("WEB");
            request.setSceneInfo(sceneInfo);

            // 5. 通过反射设置跨境专用参数(关键修改点)
            try {
                // 设置交易类型
                java.lang.reflect.Field tradeTypeField = request.getClass().getDeclaredField("tradeType");
                tradeTypeField.setAccessible(true);
                tradeTypeField.set(request, TRADE_TYPE);

                // 设置商户分类代码
                java.lang.reflect.Field mccField = request.getClass().getDeclaredField("merchantCategoryCode");
                mccField.setAccessible(true);
                mccField.set(request, MERCHANT_CATEGORY_CODE);
            } catch (Exception e) {
                log.warn("设置跨境支付扩展参数失败(不影响主要功能)", e);
            }

            // 6. 调用支付接口
            PrepayResponse response = service.prepay(request);
            return response.getCodeUrl();
        } catch (Exception e) {
            log.error("跨境支付失败 - 请检查:1.商户跨境权限 2.参数完整性 3.证书有效性", e);
            throw new RuntimeException("跨境支付创建失败: " + e.getMessage());
        }
    }
}

2025-06-19 21:16:06.375 ERROR 180488 --- [nio-8080-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException: 跨境支付创建失败: Wrong HttpStatusCode[400]

httpResponseBody[{"code":"INVALID_REQUEST","message":"暂不支持境外支付"}] HttpRequest[{"http_method":"POST","url":"https://api.mch.weixin.qq.com/v3/pay/transactions/native","uri":"https://api.mch.weixin.qq.com/v3/pay/transactions/native","headers":{"headers":{"Authorization":"WECHATPAY2-SHA256-RSA2048 mchid=\"777463044\",nonce_str=\"Ew7UiBZYweOEY5fJMT1bF19XJlbHmUFx\",timestamp=\"1750338966\",serial_no=\"7B90DEE3ABB5B5BCF3048BC24F72C0A767BCE451\",signature=\"LRuUdl2umnyp+iA4zI7CHBWMQ6XMe5ubBzHTMTHnSrKfrtwSIoF51BSmJy2sTFfFs4xiRsnj+tQlIydvyvzMpMXgJ8dM4NcbOe4Rp4Zwz30+n1gyvBXWtsJJp3/7qyRM0CkqOYgHfc1pbe0YXsX3ajHZ75nkBIHTRYN/cdSIOI0nVN0Egjf+kvBg4VrcYHHPiLJsb2NZmy4B6dMaSjYZbsn9prp+yL7ssyv0MS4puvXEwcoPmeLADsiFVvxj86Nptk2yM+kAFrPH9WLqgAWgAvOzoyDgLXSEnUghGEVwlbgNzqAfJhg21DWo8wxQLFMIrIAazKFEkrW9Bwk6LrSQQw==\"","Accept":"application/json","User-Agent":"WechatPay-Java/0.2.16 (Windows 11/10.0) Java/17.0.13 Credential/WechatPay2Credential Validator/WechatPay2Validator okhttp3/null","Content-Type":"application/json","Wechatpay-Serial":"6A00C69D09C0777622E10C03555AE96B54F63CD6"}},"body":{"body":"{\"appid\":\"wx2bd197bcb4b986a0\",\"mchid\":\"777463044\",\"description\":\"购买商品: 123\",\"out_trade_no\":\"GLOBAL_20250619211606_5738\",\"notify_url\":\"https://your-domain.com/notify\",\"amount\":{\"total\":3000,\"currency\":\"USD\"},\"scene_info\":{\"payer_client_ip\":\"8.218.65.151\",\"device_id\":\"WEB\"}}"}}]] with root cause


java.lang.RuntimeException: 跨境支付创建失败: Wrong HttpStatusCode[400]

httpResponseBody[{"code":"INVALID_REQUEST","message":"暂不支持境外支付"}] HttpRequest[{"http_method":"POST","url":"https://api.mch.weixin.qq.com/v3/pay/transactions/native","uri":"https://api.mch.weixin.qq.com/v3/pay/transactions/native","headers":{"headers":{"Authorization":"WECHATPAY2-SHA256-RSA2048 mchid=\"777463044\",nonce_str=\"Ew7UiBZYweOEY5fJMT1bF19XJlbHmUFx\",timestamp=\"1750338966\",serial_no=\"7B90DEE3ABB5B5BCF3048BC24F72C0A767BCE451\",signature=\"LRuUdl2umnyp+iA4zI7CHBWMQ6XMe5ubBzHTMTHnSrKfrtwSIoF51BSmJy2sTFfFs4xiRsnj+tQlIydvyvzMpMXgJ8dM4NcbOe4Rp4Zwz30+n1gyvBXWtsJJp3/7qyRM0CkqOYgHfc1pbe0YXsX3ajHZ75nkBIHTRYN/cdSIOI0nVN0Egjf+kvBg4VrcYHHPiLJsb2NZmy4B6dMaSjYZbsn9prp+yL7ssyv0MS4puvXEwcoPmeLADsiFVvxj86Nptk2yM+kAFrPH9WLqgAWgAvOzoyDgLXSEnUghGEVwlbgNzqAfJhg21DWo8wxQLFMIrIAazKFEkrW9Bwk6LrSQQw==\"","Accept":"application/json","User-Agent":"WechatPay-Java/0.2.16 (Windows 11/10.0) Java/17.0.13 Credential/WechatPay2Credential Validator/WechatPay2Validator okhttp3/null","Content-Type":"application/json","Wechatpay-Serial":"6A00C69D09C0777622E10C03555AE96B54F63CD6"}},"body":{"body":"{\"appid\":\"wx2bd197bcb4b986a0\",\"mchid\":\"777463044\",\"description\":\"购买商品: 123\",\"out_trade_no\":\"GLOBAL_20250619211606_5738\",\"notify_url\":\"https://your-domain.com/notify\",\"amount\":{\"total\":3000,\"currency\":\"USD\"},\"scene_info\":{\"payer_client_ip\":\"8.218.65.151\",\"device_id\":\"WEB\"}}"}}]

at com.sky.Utils.QuickStartUtil.createCrossBorderPayment(QuickStartUtil.java:123) ~[classes/:na]

at com.sky.controller.pay.WechatPayController.WechatPay(WechatPayController.java:27) ~[classes/:na]

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]

at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]

at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]

at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]

at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.22.jar:5.3.22]

at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.22.jar:5.3.22]

at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.22.jar:5.3.22]

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.22.jar:5.3.22]

at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.22.jar:5.3.22]

at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.22.jar:5.3.22]

at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1070) ~[spring-webmvc-5.3.22.jar:5.3.22]

at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.22.jar:5.3.22]

at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.22.jar:5.3.22]

at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.22.jar:5.3.22]

at javax.servlet.http.HttpServlet.service(HttpServlet.java:665) ~[javax.servlet-api-4.0.1.jar:4.0.1]

at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.22.jar:5.3.22]

at javax.servlet.http.HttpServlet.service(HttpServlet.java:750) ~[javax.servlet-api-4.0.1.jar:4.0.1]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.65.jar:9.0.65]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at com.sky.config.CorsFilter.doFilter(CorsFilter.java:27) ~[classes/:na]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.22.jar:5.3.22]

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.22.jar:5.3.22]

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.65.jar:9.0.65]

at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na]


回答关注问题邀请回答
收藏
登录 后发表内容