支付宝退款 – 永夜 https://www.shuijingwanwq.com 没有不值得去解决的问题,也没有不值得去学习的技术! Fri, 15 May 2026 09:30:58 +0000 zh-Hans hourly 1 https://wordpress.org/?v=7.0 在基于 riverslei/payment 实现支付宝退款时,报错:request get failed, msg[Invalid Arguments], sub_msg[验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配 https://www.shuijingwanwq.com/2025/07/01/9173/ https://www.shuijingwanwq.com/2025/07/01/9173/#respond Tue, 01 Jul 2025 01:50:31 +0000 https://www.shuijingwanwq.com/?p=9173 浏览量: 284 1、在基于 riverslei/payment 实现支付宝退款时,报错:request get failed, msg[Invalid Arguments], sub_msg[验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配。如图1
在基于 riverslei/payment 实现支付宝退款时,报错:request get failed, msg[Invalid Arguments], sub_msg[验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配。

图1

2、你提供的是一个 PKCS#1 格式的 RSA 私钥(以 MIIEvQ… 开头,未带头尾标识),需要通过 OpenSSL 命令将它转换为 PKCS#8 格式的 RSA 私钥,支付宝才能识别。将私钥内容复制至文件 pkcs1.pem,然后执行如下命令。 如图2
你提供的是一个 PKCS#1 格式的 RSA 私钥(以 MIIEvQ... 开头,未带头尾标识),需要通过 OpenSSL 命令将它转换为 PKCS#8 格式的 RSA 私钥,支付宝才能识别。将私钥内容复制至文件 pkcs1.pem,然后执行如下命令。

图2



$ openssl pkcs8 -topk8 -inform PEM -in pkcs1.pem -out pkcs8.pem -outform PEM -nocrypt

wangqiang@DESKTOP-F6AO3M2 MINGW64 /C/wwwroot/apply-server/src (feature/alipay)



3、最后将 pkcs8.pem 中的内容保存至 ali_rsa_private_key。如图3
最后将 pkcs8.pem 中的内容保存至 ali_rsa_private_key

图3

4、提示有所变化,提示:sign error, sign type is [RSA2]. msg: [您使用的私钥格式错误,请检查RSA私钥配置]。如图4
提示有所变化,提示:sign error, sign type is [RSA2]. msg: [您使用的私钥格式错误,请检查RSA私钥配置]

图4

5、编辑文件 vendor/riverslei/payment/src/Helpers/Rsa2Encrypt.php,


    /**
     * RSA2签名, 此处秘钥是私有秘钥
     * @param string $data 签名的数组
     * @throws \Exception
     * @return string
     * @author Leo
     */
    public function encrypt($data)
    {
        if ($this->key === false) {
            return '';
        }

        \Yii::info(
            [
                'data' => $data,
                'key' => $this->key
            ]
        );
        $res = openssl_get_privatekey($this->key);
        if (empty($res)) {
            throw new \Exception('您使用的私钥格式错误,请检查RSA私钥配置1');
        }

        openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
        openssl_free_key($res);

        //base64编码
        $sign = base64_encode($sign);
        return $sign;
    }


6、查看 $this->key,竟然有 2 个 —–BEGIN RSA PRIVATE KEY—–、—–BEGIN PRIVATE KEY—– 。如图5
查看 $this->key,竟然有 2 个 -----BEGIN RSA PRIVATE KEY-----、-----BEGIN PRIVATE KEY-----

图5

7、将 pkcs8.pem 中的内容保存至 ali_rsa_private_key 时,先清理掉 —–BEGIN RSA PRIVATE KEY—–。如图6
将 pkcs8.pem 中的内容保存至 ali_rsa_private_key 时,先清理掉 -----BEGIN RSA PRIVATE KEY-----

图6



                $aliConfig = [
                    'use_sandbox' => false, // 是否使用沙盒模式
                    'app_id' => $payee->ali_app_id,
                    'sign_type' => $payee->ali_sign_type, // RSA  RSA2
                    // 支付宝公钥字符串
                    'ali_public_key' => $payee->ali_public_key,
                    // 自己生成的密钥字符串
                    'rsa_private_key' => $payee->ali_rsa_private_key,
                    'fee_type' => 'CNY', // 货币类型  当前仅支持该字段
                ];


8、再次提示:request get failed, msg[Invalid Arguments], sub_msg[验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配,网关生成的验签字符串为 9、查看文件 vendor/riverslei/payment/src/Helpers/StrUtil.php ,发现会自动将 PKCS#1 格式的 RSA 私钥(以 MIIEvQ… 开头,未带头尾标识),转换为 旧版 PKCS#1 格式的 RSA 私钥。最后发现仍然报错:sub_msg[验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配,网关生成的验签字符串为


    /**
     * 获取rsa密钥内容
     * @param string $key 传入的密钥信息, 可能是文件或者字符串
     * @param string $type
     *
     * @return string
     */
    public static function getRsaKeyValue($key, $type = 'private')
    {
        if (is_file($key)) {// 是文件
            $keyStr = @file_get_contents($key);
        } else {
            $keyStr = $key;
        }
        if (empty($keyStr)) {
            return null;
        }

        $keyStr = str_replace(PHP_EOL, '', $keyStr);
        // 为了解决用户传入的密钥格式,这里进行统一处理
        if ($type === 'private') {
            $beginStr = '-----BEGIN RSA PRIVATE KEY-----' . PHP_EOL;
            $endStr   = PHP_EOL . '-----END RSA PRIVATE KEY-----';
        } else {
            $beginStr = '-----BEGIN PUBLIC KEY-----' . PHP_EOL;
            $endStr   = PHP_EOL . '-----END PUBLIC KEY-----';
        }

        $rsaKey = $beginStr . wordwrap($keyStr, 64, "\n", true) . $endStr;

        return $rsaKey;
    }


10、编辑 vendor/riverslei/payment/src/Supports/HttpRequest.php,验签成功


    /**
     * @param string $method
     * @param string $url
     * @param array $options
     * @return array|ResponseInterface|string|mixed
     */
    private function sendRequest(string $method, string $url, array $options = [])
    {
        \Yii::info(
            [
                '$method' => $method,
                '$url' => $url,
                '$options' => $options
            ]
        );
        // return $this->unwrapResponse($this->getHttpClient($this->getBaseOptions())->{$method}($url, $options));
        return $this->unwrapResponse($this->getHttpClient($this->getBaseOptions())->{$method}($url, [
            'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'],
            'body' => http_build_query($options['query'], '', '&', PHP_QUERY_RFC3986),
        ]));
    }


11、但是,由于响应中有乱码,进而导致 json_decode 报错。如图7
但是,由于响应中有乱码,进而导致 json_decode 报错

图7



            $ret    = $this->get($this->gatewayUrl, $params);

            if (!mb_check_encoding($ret, 'UTF-8')) {
                $ret = mb_convert_encoding($ret, 'UTF-8', 'GBK');
            }


12、报错:验签出错,请确认charset参数放在了URL查询字符串中且各参数值使用charset参数指示的字符集编码 。如图8
报错:验签出错,请确认charset参数放在了URL查询字符串中且各参数值使用charset参数指示的字符集编码

图8

13、仔细对比 请求前后的签名字符串,发现 return_url= 丢失,决定在配置时删除 return_url。原因在于


    /**
     * 获取基础数据
     * @param string $method
     * @param array $bizContent
     * @return array
     */
    private function getBaseData(string $method, array $bizContent)
    {
        $requestData = [
            'app_id'     => self::$config->get('app_id', ''),
            'method'     => $method,
            'format'     => 'JSON',
            'return_url' => self::$config->get('return_url', ''),
            'charset'    => 'utf-8',
            'sign_type'  => self::$config->get('sign_type', ''),
            'timestamp'  => date('Y-m-d H:i:s'),
            'version'    => '1.0',
            'notify_url' => self::$config->get('notify_url', ''),
            // 'app_auth_token' => '', // 暂时不用
            'biz_content' => json_encode($bizContent, JSON_UNESCAPED_UNICODE),
        ];
        return ArrayUtil::arraySort($requestData);
    }




echo html_entity_decode('app_id=2021005146654430&biz_content={"out_trade_no":"1831248803313247","refund_amount":"0.01","refund_currency":"CNY","refund_reason":"Refund for Conference Registration Fee (Ticket)","out_request_no":"1831248803313311"}&charset=utf-8&format=JSON&method=alipay.trade.refund&notify_url=https://5347-43-249-50-182.ngrok-free.app/ali-payment/notify-ticket-order/1831248803313247&sign_type=RSA2&timestamp=2025-05-10 16:39:56&version=1.0');

// 请求前的签名字符串
// app_id=2021005146654430&biz_content={"out_trade_no":"1831248803313247","refund_amount":"0.01","refund_currency":"CNY","refund_reason":"Refund for Conference Registration Fee (Ticket)","out_request_no":"1831248803313311"}&charset=utf-8&format=JSON&method=alipay.trade.refund&notify_url=https://5347-43-249-50-182.ngrok-free.app/ali-payment/notify-ticket-order/1831248803313247&return_url=&sign_type=RSA2&timestamp=2025-05-10 16:39:56&version=1.0

// 请求后报错,支付宝使用的签名字符串
// app_id=2021005146654430&biz_content={"out_trade_no":"1831248803313247","refund_amount":"0.01","refund_currency":"CNY","refund_reason":"Refund for Conference Registration Fee (Ticket)","out_request_no":"1831248803313311"}&charset=utf-8&format=JSON&method=alipay.trade.refund&notify_url=https://5347-43-249-50-182.ngrok-free.app/ali-payment/notify-ticket-order/1831248803313247&sign_type=RSA2&timestamp=2025-05-10 16:39:56&version=1.0


14、支付宝返回的验签字符串中确实不会包含空值字段,例如 return_url=(空值)这一项,而你在参与签名时包含了它,导致签名字符串不一致,从而验签失败。最终决定调整配置


                $aliConfig = [
                    'use_sandbox' => false, // 是否使用沙盒模式
                    'app_id' => $payee->ali_app_id,
                    'sign_type' => $payee->ali_sign_type, // RSA  RSA2
                    // 支付宝公钥字符串
                    'ali_public_key' => $payee->ali_public_key,
                    // 自己生成的密钥字符串
                    'rsa_private_key' => $payee->ali_rsa_private_key,
                    'limit_pay' => [
                        // 'balance', // 余额
                        // 'moneyFund', // 余额宝
                        // 'debitCardExpress', // 借记卡快捷
                        // 'creditCard', // 信用卡
                        // 'creditCardExpress', // 信用卡快捷
                        // 'creditCardCartoon', // 信用卡卡通
                        // 'credit_group', // 信用支付类型(包含信用卡卡通、信用卡快捷、花呗、花呗分期)
                    ], // 用户不可用指定渠道支付当有多个渠道时用“,”分隔
                    // 与业务相关参数
                    'notify_url' => 'notify_url',
                    'return_url' => 'return_url',
                    'fee_type' => 'CNY', // 货币类型  当前仅支持该字段
                ];



15、不再报错。打印退款的响应


$result = $client->refund($refundData);

Yii::info(
	[
		'result' => $result,
		'data' => $refundData,
	],
	'refund ali'
);

	[
    'result' => [
        'code' => '10000',
        'msg' => 'Success',
        'buyer_logon_id' => 'shu***@163.com',
        'fund_change' => 'Y',
        'gmt_refund_pay' => '2025-05-10 17:01:59',
        'out_trade_no' => '1831248803313320',
        'refund_detail_item_list' => [
            [
                'amount' => '0.01',
                'fund_channel' => 'ALIPAYACCOUNT',
            ],
        ],
        'refund_fee' => '0.01',
        'send_back_fee' => '0.01',
        'trade_no' => '2025051022001491671421159148',
        'buyer_open_id' => '067IqA-DLOIYEoiWWh1KNCyoaiY-qUzekwwoGX_3VQKI9s7',
    ],
    'data' => [
        'trade_no' => '1831248803313320',
        'refund_fee' => '0.01',
        'reason' => 'Refund for Conference Registration Fee (Ticket)',
        'refund_no' => '1831248803313321',
    ],
]


]]>
https://www.shuijingwanwq.com/2025/07/01/9173/feed/ 0