为什么源码交易离不开微信支付?

在源码交易领域,微信支付几乎是最核心的支付方式。国内开发者习惯使用微信扫码或小程序内支付购买源码产品,而支付宝、银联等渠道的使用率远不及微信。对于搭建源码商城的站长来说,稳定、安全地接入微信支付是业务运转的基础。

本文将从实战角度出发,完整讲解在源码交易场景中接入微信支付的全流程:Native 支付(扫码)、JSAPI 支付(公众号/小程序内支付)、支付回调处理、自动发货系统集成,以及日常运维中的常见问题和最佳实践。所有代码基于 PHP + MySQL 环境,并附有 Python 参考实现。

如果你还没有自己的源码商城系统,不妨先看看我们的 源码商城产品,我们提供了完整的商城源码,内置微信支付对接模块,开箱即用。

一、微信支付接入前的准备

1.1 开通微信支付商户平台

首先需要在 微信支付商户平台 注册商户号。注册完成后,需要获取以下关键参数:

  • 商户号(mchid):商户平台的唯一标识
  • API 密钥(APIv3 Key):用于 API 签名的 32 位密钥
  • 商户证书(pem 格式):商户私钥和证书序列号
  • 微信支付平台证书:验证微信服务器响应的证书

1.2 配置支付回调域名

在商户平台 → 产品中心 → 开发配置中,设置 JSAPI 支付授权目录和 Native 支付回调链接。以源码商城为例,假设你的商城部署在 https://greenfield.ltd/store/,需要配置:

# JSAPI 支付授权目录
https://greenfield.ltd/store/order/

# Native 支付回调 URL
https://greenfield.ltd/store/order/pay_notify.php

# 退款回调 URL
https://greenfield.ltd/store/order/refund_notify.php

二、Native 支付(扫码支付)实战

Native 支付是源码交易最常用的方式——用户打开商品页,选择微信支付,页面上展示二维码,扫码完成支付。下面给出完整的 PHP 实现。

2.1 统一下单接口

<?php
// wechat_native_pay.php — Native 支付下单

function createNativeOrder($orderNo, $amount, $description) {
    $merchantId = 'YOUR_MCHID';
    $serialNo   = 'YOUR_CERT_SERIAL';
    $apiKey     = 'YOUR_API_V3_KEY';
    
    $url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/native';
    
    $body = json_encode([
        'mchid'        => $merchantId,
        'out_trade_no' => $orderNo,
        'appid'        => 'YOUR_APPID',
        'description'  => $description,
        'notify_url'   => 'https://greenfield.ltd/store/order/pay_notify.php',
        'amount'       => ['total' => intval($amount * 100), 'currency' => 'CNY']
    ]);
    
    // 生成签名(Wechatpay-Signature)
    $nonce  = bin2hex(random_bytes(16));
    $timestamp = time();
    $message = "POST\n/v3/pay/transactions/native\n{$timestamp}\n{$nonce}\n{$body}\n";
    
    $privateKey = openssl_get_privatekey(file_get_contents('/path/to/apiclient_key.pem'));
    openssl_sign($message, $signature, $privateKey, 'sha256WithRSAEncryption');
    $sign = base64_encode($signature);
    
    $token = sprintf(
        'mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
        $merchantId, $nonce, $timestamp, $serialNo, $sign
    );
    
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST       => true,
        CURLOPT_POSTFIELDS => $body,
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'Accept: application/json',
            "Wechatpay-Serial: {$serialNo}",
            "Authorization: WECHATPAY2-SHA256-RSA2048 {$token}"
        ],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    
    $result = json_decode(curl_exec($ch), true);
    curl_close($ch);
    
    // 返回 code_url 即为支付二维码链接
    return $result['code_url'] ?? null;
}

// 使用示例
$codeUrl = createNativeOrder('ORD20260630001', 99.00, '源码商城 - Codex Desktop授权');
// 将 $codeUrl 生成二维码展示给用户
?>

返回的 code_url 是一段 URL,需要用二维码生成库(如 phpqrcode 或前端 qrcode.js)渲染为二维码图片展示给用户。

2.2 前端扫码展示

<div class="pay-qrcode">
  <div id="qrcode"></div>
  <p class="tip">请使用微信扫码支付</p>
</div>

<script src="https://cdn.jsdelivr.net/npm/qrcodejs@1.0.0/qrcode.min.js"></script>
<script>
new QRCode(document.getElementById('qrcode'), {
  text: '',
  width: 200,
  height: 200
});

// 轮询支付状态
const pollTimer = setInterval(async () => {
  const res = await fetch('/store/order/check.php?order=' + orderNo);
  const data = await res.json();
  if (data.status === 'success') {
    clearInterval(pollTimer);
    window.location.href = '/store/order/success.html?order=' + orderNo;
  }
}, 2000);
</script>

三、支付回调与验签

支付回调是整套系统的"心脏"——只有正确处理好回调通知,才能实现自动发货。微信支付在用户完成支付后,会向你的 notify_url 发送 POST 请求,携带完整的支付结果信息。

3.1 回调处理示例

<?php
// pay_notify.php — 微信支付回调处理

$incomingBody = file_get_contents('php://input');
$headers = getallheaders();

// 1. 获取微信签名字段
$wechatpaySignature = $headers['Wechatpay-Signature'] ?? '';
$wechatpayTimestamp  = $headers['Wechatpay-Timestamp'] ?? '';
$wechatpayNonce      = $headers['Wechatpay-Nonce'] ?? '';
$wechatpaySerial     = $headers['Wechatpay-Serial'] ?? '';

// 2. 构造验签名串
$message = "{$wechatpayTimestamp}\n{$wechatpayNonce}\n{$incomingBody}\n";

// 3. 获取微信平台证书公钥(建议缓存)
$platformPublicKey = getWechatPlatformCert($wechatpaySerial);

// 4. 验证签名
$ok = openssl_verify(
    $message,
    base64_decode($wechatpaySignature),
    $platformPublicKey,
    'sha256WithRSAEncryption'
);

if (!$ok) {
    http_response_code(401);
    exit('FAIL');
}

// 5. 解密资源(AES-256-GCM)
$data = json_decode($incomingBody, true);
$resource = $data['resource'];
$ciphertext  = base64_decode($resource['ciphertext']);
$associatedData = $resource['associated_data'];
$nonce = $resource['nonce'];

$decrypted = openssl_decrypt(
    $ciphertext,
    'aes-256-gcm',
    $apiKey,
    OPENSSL_RAW_DATA,
    $nonce,
    '',
    16
);

$payResult = json_decode($decrypted, true);

// 6. 处理订单 — 更新状态并触发发货
$orderNo   = $payResult['out_trade_no'];
$tradeNo   = $payResult['transaction_id'];
$payerOpenid = $payResult['payer']['openid'];
$totalFee  = $payResult['amount']['total']; // 单位:分

// 更新数据库订单状态
$db->query("UPDATE orders SET status='paid', trade_no='{$tradeNo}', paid_at=NOW() 
             WHERE order_no='{$orderNo}' AND status='pending'");

// 触发自动发货(详见下一节)
autoDeliverProduct($orderNo);

// 7. 应答微信 — 必须返回 200 + SUCCESS
http_response_code(200);
echo '{"code":"SUCCESS","message":"成功"}';
?>
💡 注意事项:回调处理幂等性非常重要——微信可能会重复发送多次回调通知,你的处理逻辑必须保证多次执行不会产生重复发货。建议用数据库唯一索引或 Redis 锁来保证幂等。

四、自动发货系统集成

源码交易和实物商品不同,用户付款后期望立即获得源码下载链接或授权码。自动发货系统就是支付成功后的"最后一公里"。

4.1 发货逻辑实现

<?php
// auto_deliver.php — 自动发货

function autoDeliverProduct($orderNo) {
    // 获取订单信息
    $order = $db->query("SELECT * FROM orders WHERE order_no='{$orderNo}'")->fetch();
    
    switch ($order['product_type']) {
        case 'codex_desktop':
            // Codex Desktop: 生成授权码并发送
            $license = generateLicenseKey($order['id']);
            $db->query("INSERT INTO licenses (order_id, license_key, status) 
                         VALUES ('{$order['id']}', '{$license}', 'active')");
            
            // 发送通知(站内信 + 可选邮件)
            sendUserNotification($order['user_id'], 
                "您的 Codex Desktop 授权码已生成:{$license}");
            break;
            
        case 'card_qr_v3':
            // 转卡码系统:直接发货卡密
            $card = assignCard($order['product_id'], $order['user_id']);
            sendUserNotification($order['user_id'], 
                "您的卡密:{$card['card_no']},有效期至:{$card['expire_at']}");
            break;
            
        case 'source_code':
            // 源码下载:生成临时下载链接(有限次/限时)
            $token = bin2hex(random_bytes(32));
            $db->query("INSERT INTO download_tokens (order_id, token, expires_at) 
                         VALUES ('{$order['id']}', '{$token}', DATE_ADD(NOW(), INTERVAL 24 HOUR))");
            $downloadUrl = "https://greenfield.ltd/store/download.php?token={$token}";
            sendUserNotification($order['user_id'], "下载链接:{$downloadUrl}(24小时内有效)");
            break;
    }
}
?>

我们的 源码商城系统 内置了完善的自动发货模块,支持 Codex Desktop 授权码自动发放、转卡码系统卡密自动分配、源码下载链接生成等多种发货方式,无需从零开发。

五、JSAPI 支付(小程序/H5 内支付)

如果你的源码商城还有小程序端或微信公众号端,JSAPI 支付是必须对接的。JSAPI 支付流程比 Native 多一个步骤:需要先获取用户的 openid

5.1 获取用户 OpenID

<?php
// 通过 OAuth2 获取用户 openid
$appid     = 'YOUR_APPID';
$appsecret = 'YOUR_APPSECRET';
$code      = $_GET['code']; // 微信回调传来的临时 code

$url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
     . "appid={$appid}&secret={$appsecret}&code={$code}&grant_type=authorization_code";

$resp = json_decode(file_get_contents($url), true);
$openid = $resp['openid']; // 用户唯一标识
?>

5.2 JSAPI 下单

<?php
// JSAPI 下单与 Native 类似,但需传入 openid
$body = json_encode([
    'mchid'        => $merchantId,
    'out_trade_no' => $orderNo,
    'appid'        => $appid,
    'description'  => $description,
    'notify_url'   => 'https://greenfield.ltd/store/order/pay_notify.php',
    'amount'       => ['total' => intval($amount * 100), 'currency' => 'CNY'],
    'payer'        => ['openid' => $openid]
]);

// POST 到 https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
// 返回 prepay_id,传给前端调起支付
?>

5.3 前端调起支付

<script>
// 后端返回的 prepay 参数
const payParams = {
  appId:     'wx...',
  timeStamp: '...',
  nonceStr:  '...',
  package:   'prepay_id=...',
  signType:  'RSA',
  paySign:   '...'
};

wx.chooseWXPay({
  ...payParams,
  success: function(res) {
    // 支付成功,后端会处理回调,这里可以跳转到成功页
    window.location.href = '/store/order/success.html?order=' + orderNo;
  },
  fail: function(err) {
    alert('支付失败:' + err.errMsg);
  }
});
</script>

六、支付对账与异常处理

6.1 每日对账脚本

生产环境每天建议跑一次对账,确保本地订单状态与微信商户平台一致:

#!/bin/bash
# daily_reconcile.sh — 每日对账脚本 (cron 每天凌晨 2 点执行)

DATE=$(date -d "yesterday" "+%Y-%m-%d")
BALANCE_URL="https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=${DATE}&bill_type=ALL"

# 下载账单并比对本地数据库
php /var/www/html/store/scripts/reconcile.php --date=$DATE

# 记录差异到日志
if [ $? -ne 0 ]; then
    echo "[ALERT] 对账异常!日期: $DATE" | mail -s "支付对账告警" admin@greenfield.ltd
fi

6.2 常见问题排查

问题可能原因解决方案
回调收不到防火墙/Nginx 未放行 IP 范围放行微信回调 IP 段,检查 Nginx 日志
签名验证失败APIv3 Key 错误或证书过期重新下载商户证书,检查平台证书序列号
自动发货未触发回调未正确处理检查回调日志,手动触发发货
二维码扫码提示"已过期"code_url 有效期 2 小时重新下单生成新二维码
JSAPI "当前页面未注册"授权目录配置不正确检查 JSAPI 支付授权目录是否精确匹配

七、安全最佳实践总结

在源码交易中接入微信支付,安全是重中之重。总结几条核心原则:

  1. 永远在服务端做签名:不要在客户端暴露 API 密钥和商户证书
  2. 回调通知必须验签:任何未通过签名的请求都拒绝处理
  3. 幂等处理不可少:重复回调不会导致重复发货
  4. 金额以分为单位:避免浮点数精度问题
  5. 订单号要有业务意义:建议格式 日期+用户ID+序号,便于排查
  6. 使用 APIv3 接口:v2 接口已逐步下线,新项目直接上 v3
  7. 定期更换 API 密钥:每 3-6 个月更换一次商户 API 密钥

微信支付接入看似简单,实际生产环境中要处理的各种边界情况非常多。如果你希望快速搭建一个带有完整微信支付对接、自动发货系统的源码商城,不妨直接使用我们的 源码商城产品——我们不仅提供了完整的支付模块源码,还包含了转卡码系统、Codex Desktop 自动分发等功能,帮你节省大量开发时间。

八、用 Python 实现的参考实现

如果你更习惯 Python,这里也提供一个使用 wechatpayv3 库的参考实现片段:

# pay.py — Python 版微信支付 Native 下单
from wechatpayv3 import WeChatPay, WeChatPayException

wxpay = WeChatPay(
    appid      = 'YOUR_APPID',
    mchid      = 'YOUR_MCHID',
    api_key    = 'YOUR_API_V3_KEY',
    private_key_path = '/path/to/apiclient_key.pem',
    cert_serial_no   = 'YOUR_CERT_SERIAL',
)

try:
    result = wxpay.native_pay(
        description = '源码商城 - 转卡码系统授权',
        out_trade_no = 'ORD20260630002',
        amount       = 19900,  # 单位:分 = ¥199
        notify_url   = 'https://greenfield.ltd/store/order/pay_notify.php',
    )
    code_url = result['code_url']
    print(f"支付二维码链接: {code_url}")
except WeChatPayException as e:
    print(f"下单失败: {e}")

Python 版本非常适合在自动化脚本中使用,比如配合 Celery 进行异步支付状态检查。

结语

微信支付接入是源码商城的技术基石之一。从 Native 扫码到 JSAPI 内支付,从回调验签到自动发货,每个环节都需要精心设计和充分的异常处理。希望本文的实战代码能帮助你少走弯路,快速搭建一个稳定可靠的支付系统。

如果你对转卡码系统的支付对接、Codex Desktop 授权发放机制感兴趣,欢迎访问 源码商城 了解更多产品详情。我们提供完整的商城源码,内置微信支付、支付宝支付双通道,支持自动发货、代理分润等高级功能。