当前位置:首页 > 技术 > 正文内容

微信支付 JSAPI 统一下单接口调用指南

访客 技术 2026年6月27日 1

在获取用户 openid 后,下一步是调用微信支付统一下单接口生成预支付交易单。该接口是微信支付的核心入口,适用于除付款码支付外的所有场景。

接口地址

https://api.mch.weixin.qq.com/pay/unifiedorder
https://api2.mch.weixin.qq.com/pay/unifiedorder(备用)

必备请求参数(JSAPI 场景)

参数名说明
appid微信公众号或小程序的 AppID
mch_id微信支付分配的商户号(10位数字)
nonce_str随机字符串,用于增强签名安全性
sign通过签名算法生成的签名字符串
sign_type签名算法类型:MD5 或 HMAC-SHA256
body商品或订单描述
out_trade_no商户系统内部唯一订单号
total_fee订单总金额,单位为分(整数)
spbill_create_ip发起支付请求的客户端 IP 地址
notify_url支付结果异步通知回调地址
trade_type交易类型,JSAPI 场景固定为 "JSAPI"
openid微信用户在商户 appid 下的唯一标识
device_info设备信息,非必填,PC网页或公众号支付建议传 "WEB"

签名计算流程

  1. 过滤空值参数,排除 sign 字段
  2. 按参数名 ASCII 码升序排列
  3. 拼接为 URL 键值对格式:key1=value1&key2=value2...
  4. 末尾追加 &key=商户API密钥
  5. 执行 MD5 或 HMAC-SHA256 运算,结果转大写

微信提供在线签名验证工具,可选择签名类型为 XML 格式进行校验。

签名实现代码(PHP)

<?php
class PaymentSigner
{
    /**
     * 生成请求签名
     * @param array $params 待签名参数集合
     * @param string $apiKey 商户API密钥
     * @param bool $useSha256 是否使用HMAC-SHA256算法
     * @return string 大写签名字符串
     */
    public static function createSign(array $params, string $apiKey, bool $useSha256 = false): string
    {
        // 过滤空值并排序
        $filtered = self::filterAndSort($params);
        
        // 构建待签名字符串
        $stringToSign = self::buildQueryString($filtered);
        $stringToSign .= "&key=" . $apiKey;
        
        // 执行签名运算
        if ($useSha256) {
            $signature = hash_hmac('sha256', $stringToSign, $apiKey);
        } else {
            $signature = md5($stringToSign);
        }
        
        return strtoupper($signature);
    }
    
    /**
     * 过滤空值并按ASCII排序
     */
    private static function filterAndSort(array $data): array
    {
        $result = [];
        foreach ($data as $field => $value) {
            if ($field !== 'sign' && $value !== '' && !is_array($value)) {
                $result[$field] = $value;
            }
        }
        ksort($result);
        return $result;
    }
    
    /**
     * 构建URL编码格式的查询字符串
     */
    private static function buildQueryString(array $data): string
    {
        $pairs = [];
        foreach ($data as $k => $v) {
            $pairs[] = $k . '=' . $v;
        }
        return implode('&', $pairs);
    }
}

组装XML请求数据

<?php
class XmlBuilder
{
    /**
     * 将数组转换为微信支付XML格式
     */
    public static function fromArray(array $data): string
    {
        $xml = "<xml>\n";
        foreach ($data as $tag => $value) {
            $xml .= "<{$tag}>{$value}</{$tag}>\n";
        }
        $xml .= "</xml>";
        return $xml;
    }
}

生成的XML示例:

<xml>
    <appid>wxd678efh567hg6787</appid>
    <mch_id>1230000109</mch_id>
    <device_info>WEB</device_info>
    <nonce_str>5K8264ILTKCH16CQ2502SI8ZNMTM67VS</nonce_str>
    <body>腾讯充值中心-QQ会员充值</body>
    <out_trade_no>20150806125346</out_trade_no>
    <total_fee>888</total_fee>
    <spbill_create_ip>123.12.12.123</spbill_create_ip>
    <notify_url>https://example.com/wxpay/notify</notify_url>
    <trade_type>JSAPI</trade_type>
    <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
    <sign>C380BEC2BFD727A4B6845133519F3AD6</sign>
</xml>

HTTP请求发送

<?php
class HttpClient
{
    /**
     * 发送POST请求至微信支付接口
     */
    public static function postXml(string $url, string $xmlBody, int $timeout = 30): string|false
    {
        $handler = curl_init();
        
        curl_setopt_array($handler, [
            CURLOPT_URL => $url,
            CURLOPT_TIMEOUT => $timeout,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $xmlBody,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HEADER => false,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => false,
        ]);
        
        $response = curl_exec($handler);
        
        if ($response === false) {
            $errCode = curl_errno($handler);
            curl_close($handler);
            error_log("CURL请求失败,错误码: {$errCode}");
            return false;
        }
        
        curl_close($handler);
        return $response;
    }
}

响应结果解析

接口返回XML数据,关键字段说明:

字段含义
return_code通信标识:SUCCESS/FAIL
return_msg通信错误信息
result_code业务结果:SUCCESS/FAIL
prepay_id预支付交易会话标识(调起支付必需)
trade_type交易类型

成功响应示例:

<xml>
    <return_code><![CDATA[SUCCESS]]></return_code>
    <return_msg><![CDATA[OK]]></return_msg>
    <appid><![CDATA[wxd678efh567hg6787]]></appid>
    <mch_id><![CDATA[1230000109]]></mch_id>
    <nonce_str><![CDATA[SMIpZtHhPPyTezlY]]></nonce_str>
    <sign><![CDATA[7215B1BAB1C08A4887AAB0ECB2A60447]]></sign>
    <result_code><![CDATA[SUCCESS]]></result_code>
    <prepay_id><![CDATA[wx201410272009395522657a690399285100]]></prepay_id>
    <trade_type><![CDATA[JSAPI]]></trade_type>
</xml>

获取到 prepay_id 后,即可用于前端调起微信支付。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

linux screen 用法详情 (nohup 的替代方案)

一、screen 是什么?能干嘛?screen 是一个终端复用器,可以:在一个 SSH 会话中开多个“虚拟终端”SSH 断线后,程序仍然在后台运行随时重新连接到原来的会话特别适合:nohup 的替代方案跑脚本 / 爬虫 / 训练模型运维、远程开发二、安装 screen# CentOS / Rocky / Almayum install -y screen# Debian / Ubuntuapt i...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。