Skip to content

微信支付网站对接与商品下单完整开发文档(2026最新版·新手友好)

目录

  1. 文档概述
  2. 第一部分:前期准备与账号申请
  3. 第二部分:微信支付商户平台核心配置
  4. 第三部分:商品下单完整流程详解
  5. 第四部分:微信支付接口开发
  6. 第五部分:测试与上线
  7. 第六部分:异常情况处理
  8. 第七部分:新手必踩坑与避坑指南
  9. 第八部分:推荐资源与时间预估
  10. 附录:核心代码伪代码示例

文档概述

本文档专为首次对接微信支付的开发者编写,详细讲解了从资质准备→账号申请→商户配置→商品下单流程→支付接口开发→测试上线的全流程。文档基于2026年最新的微信支付APIv3版本编写,重点标注了新手最容易出错的环节和最佳实践。

本文档适用于:

  • 有营业执照的企业或个体工商户网站
  • PC端扫码支付、微信内JSAPI支付、微信外H5支付场景
  • 使用Java、PHP、Python、Node.js、Go等主流语言开发的网站

第一部分:前期准备与账号申请

这是最基础也是最关键的一步,所有后续开发都依赖这些账号和资质。

1.1 必备资质(商家提供)

  • 有效期内的营业执照(个体工商户或企业均可)
  • 法人身份证正反面照片
  • 对公银行账户信息(企业必须;个体工商户可使用法人个人银行卡)
  • 网站ICP备案证明(必须,微信支付要求对接的网站已完成ICP备案)

1.2 账号申请顺序(必须严格按此顺序)

1.2.1 申请微信公众号(服务号)

  • 类型选择:服务号(订阅号无法申请微信支付)
  • 主体类型:根据商家资质选择"企业"或"个体工商户"
  • 完成公众号认证(300元/年,必须认证才能申请支付)
  • 记录下公众号的AppIDAppSecret(在公众号后台→开发→基本配置)

1.2.2 申请微信支付商户号

  • 入口:公众号后台→微信支付→申请开通
  • 按提示填写商家信息、上传资质、绑定对公账户
  • 微信会向对公账户打一笔小额验证款(0.01-1元),输入验证金额完成审核
  • 审核通过后,会收到商户号(mch_id,10位数字)和商户平台登录账号
  • 审核时间通常为1-2个工作日

1.2.3 (可选但推荐)申请微信开放平台账号

  • 如果你的网站需要支持PC端扫码支付+移动端H5支付,建议申请
  • 在开放平台创建"网站应用",完成审核后获取网站应用的AppID
  • 将该网站应用与上述商户号进行绑定(商户平台→产品中心→APPID授权管理)

第二部分:微信支付商户平台核心配置

这一步是新手出错率最高的环节,每一项配置都要精确无误,否则支付会直接失败。配置修改后大约5-10分钟生效。

2.1 API安全配置(账户中心→API安全)

  • 设置APIv3密钥(强烈推荐使用v3版本接口,比v2更安全简单)
    • 生成一个32位的随机字符串作为密钥(不要用简单密码)
    • 妥善保存,后续开发会用到,且绝对不能泄露
  • 下载API证书
    • 点击"申请API证书",按指引生成并下载证书压缩包
    • 解压后得到apiclient_cert.pemapiclient_key.pem两个文件
    • 证书用于退款、撤销订单等敏感接口,普通支付接口不需要

2.2 支付产品配置(产品中心→开发配置)

支付场景配置项配置要求示例
微信内JSAPI支付JSAPI支付授权目录必须以/结尾,精确到最后一级目录
必须是HTTPS开头
域名必须与ICP备案主体一致
https://www.example.com/pay/
微信外H5支付H5支付授权域名不要加https://和路径
必须通过ICP备案
www.example.com
PC端扫码支付扫码支付回调URL必须是公网可访问的HTTPS地址
不能有端口(除非是443端口)
不能有重定向
https://www.example.com/api/wxpay/notify

2.3 重要提醒

  • 所有域名必须是HTTPS开头(微信支付强制要求)
  • 域名必须与ICP备案的主体一致
  • 配置修改后大约5-10分钟生效,不要立即测试
  • 回调地址不能携带任何参数

第三部分:商品下单完整流程详解

从用户点击"立即购买"到订单完成的完整流程,包含前后端分工和与微信支付的交互点。

3.1 整体流程总览

用户操作:点击立即购买 → 确认订单信息 → 选择微信支付 → 完成支付 → 查看支付结果
系统执行:商品信息校验 → 库存预占 → 创建订单 → 调用微信统一下单 → 前端唤起支付

订单完成 ← 更新订单状态 ← 扣减实际库存 ← 验证微信回调 ← 微信异步通知支付结果

3.2 分步骤详细讲解

第一步:用户点击"立即购买"或"去结算"(前端发起)

用户操作:在商品详情页选择规格(颜色、尺码等),点击"立即购买";或在购物车勾选商品,点击"去结算"

前端做什么

  1. 收集用户选择的商品信息:商品ID、SKU ID(如果有规格)、购买数量
  2. 跳转到"确认订单"页面

后端做什么(可选但推荐):

  • 提前查询一次商品的当前库存和最新价格,在确认订单页展示
  • 避免用户在商品详情页停留过久,库存或价格已经变化

第二步:用户确认订单信息并提交(核心环节1)

用户操作

  • 确认收货地址、联系电话
  • 确认商品信息、数量、单价、总价
  • 选择支付方式(这里我们只讲微信支付)
  • 点击"提交订单"按钮

后端核心执行流程(必须在一个数据库事务中完成)

1. 【参数校验】验证商品是否存在、是否上架、购买数量是否合法
2. 【库存校验】检查商品实际可售库存是否 ≥ 购买数量
   ✅ 新手必看:这里是"检查",不是"扣减"!
3. 【价格计算】
   - 计算商品总金额 = 单价 × 数量
   - 计算优惠金额(优惠券、满减等)
   - 计算实付金额 = 商品总金额 - 优惠金额 + 运费(如有)
4. 【生成唯一订单号】
   - 推荐格式:年月日时分秒 + 6位随机数(如:20260530163045123456)
   - 绝对不能重复!微信支付要求out_trade_no在商户号下唯一
5. 【创建订单】
   - 保存订单主表:订单号、用户ID、实付金额、订单状态=待支付、创建时间、支付超时时间
   - 保存订单明细表:每个商品的ID、SKU ID、名称、单价、数量、小计
   - 保存收货地址信息
6. 【预占库存(锁定库存)】✅ 电商界主流最佳实践
   - 将商品的"可售库存"减少购买数量
   - 将商品的"锁定库存"增加购买数量
   - 例如:原可售库存100,用户买2件 → 可售库存98,锁定库存2
7. 【设置支付超时】
   - 给订单设置一个支付有效期(通常15-30分钟)
   - 超时后系统自动取消订单,释放锁定的库存

为什么要"下单预占库存"而不是"支付成功再扣库存"?

  • ✅ 防止超卖:如果100个人同时买最后1件商品,下单时预占库存,只有第一个人能成功下单
  • ✅ 用户体验好:用户下单后就知道商品已经被锁定,不会出现付完款才被告知没货的情况
  • ❌ 缺点:会有恶意下单占用库存的情况,但可以通过"超时自动取消"解决

第三步:调用微信支付统一下单接口(核心环节2)

后端做什么

  1. 检查订单状态是否为"待支付",且未超时
  2. 调用微信支付官方SDK的"统一下单"方法
  3. 传入关键参数(详见第四部分)
  4. 接收微信返回的支付参数并返回给前端

前端做什么

  • PC端:将后端返回的code_url生成二维码,显示"请使用微信扫码支付"
  • 微信内:使用微信JS-SDK,传入后端返回的支付参数,直接唤起微信支付窗口
  • 微信外:直接跳转到后端返回的h5_url,用户在微信中完成支付

第四步:用户完成支付

用户操作

  • 扫码支付:打开微信"扫一扫",扫描二维码,输入密码完成支付
  • JSAPI/H5支付:在微信中点击"确认支付",输入密码完成支付

系统此时的状态

  • 订单状态仍然是"待支付"
  • 库存仍然是"锁定"状态
  • 前端显示"支付中,请稍候...",并开始轮询后端查询订单状态

第五步:微信异步通知支付结果(核心环节3,重中之重)

这是整个流程中最关键的一步!绝对不能信任前端返回的支付结果!

微信做什么

  • 用户支付成功后,微信服务器会异步POST请求你之前配置的notify_url
  • 请求内容包含:订单号、支付金额、支付时间、微信支付订单号等信息
  • 如果你的接口没有返回成功,微信会在24小时内多次重试通知(间隔:15/15/30/180/1800/1800/1800/1800/3600秒)

后端必须做的3件事

1. 【验证签名】✅ 绝对不能省略!
   - 使用你的APIv3密钥验证微信发送的签名
   - 防止有人伪造支付成功的通知,骗取商品
2. 【验证订单信息】
   - 验证订单号是否存在
   - 验证订单状态是否为"待支付"
   - 验证支付金额是否与订单实付金额一致
3. 【更新订单状态并完成业务逻辑】
   - 将订单状态从"待支付"改为"已支付/待发货"
   - 记录微信支付订单号和支付时间
   - 将商品的"锁定库存"减少购买数量
   - 将商品的"已售库存"增加购买数量
   - (可选)发送短信/邮件通知用户支付成功
   - (可选)通知商家有新订单需要处理

最后必须返回给微信

json
{"code": "SUCCESS", "message": "OK"}
  • 只有返回这个,微信才会停止重试通知
  • 回调接口必须在5秒内返回结果

第六步:前端展示支付结果

前端做什么

  • 持续轮询后端的"订单查询接口"(通常每2-3秒查询一次)
  • 当查询到订单状态变为"已支付"时,跳转到"支付成功"页面
  • 如果查询到订单已超时取消,跳转到"支付失败"页面

为什么需要前端轮询?

  • 微信的异步通知可能会有延迟(通常几秒到几十秒)
  • 极少数情况下,微信的通知可能会丢失
  • 前端轮询可以作为回调的补充,确保用户能及时看到支付结果

第七步:订单后续处理

  • 待发货:商家看到新订单后,进行拣货、打包、发货
  • 已发货:商家在系统中输入物流单号,订单状态变为"已发货/待收货"
  • 已完成:用户确认收货,或系统自动确认收货(通常发货后15天),订单状态变为"已完成"
  • 已取消:用户超时未支付,或用户主动取消订单,系统自动释放锁定的库存

3.3 订单状态流转图(标准电商模式)

待支付
  ├─→ 用户支付成功 → 已支付/待发货 → 商家发货 → 已发货/待收货 → 用户确认收货 → 已完成
  └─→ 用户取消订单/超时未支付 → 已取消(释放库存)

已支付/待发货
  └─→ 用户申请退款 → 退款中 → 退款成功 → 已关闭(回滚库存)

已发货/待收货
  └─→ 用户申请退货 → 退货中 → 退货成功 → 已关闭(回滚库存)

第四部分:微信支付接口开发

强烈建议使用微信支付官方SDK,不要自己手写签名和接口调用,能避免90%的错误。官方SDK支持Java、PHP、Python、Node.js、Go等主流语言。

4.1 核心接口列表(APIv3版本)

接口名称接口地址用途
统一下单(Native)https://api.mch.weixin.qq.com/v3/pay/transactions/nativePC端扫码支付
统一下单(JSAPI)https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi微信内浏览器支付
统一下单(H5)https://api.mch.weixin.qq.com/v3/pay/transactions/h5微信外浏览器支付
查询订单https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}主动查询订单状态
关闭订单https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}/close关闭未支付的订单
申请退款https://api.mch.weixin.qq.com/v3/refund/domestic/refunds申请退款(需要API证书)

4.2 统一下单接口必填参数

json
{
  "appid": "你的公众号/网站应用AppID",
  "mchid": "你的微信支付商户号",
  "description": "商品描述(最多127字)",
  "out_trade_no": "商户订单号(唯一,32个字符内)",
  "amount": {
    "total": 实付金额(单位是分!不是元!),
    "currency": "CNY"
  },
  "notify_url": "你的支付回调接口地址",
  "trade_type": "支付类型(NATIVE/JSAPI/H5)"
}

4.3 统一下单接口返回结果

  • NATIVE支付:返回code_url(二维码内容,前端生成二维码即可)
  • JSAPI支付:返回prepay_id(用于前端唤起微信支付)
  • H5支付:返回h5_url(前端直接跳转该地址即可)

4.4 支付回调接口开发要点

  • 回调接口为POST请求,数据以JSON格式传输
  • 必须验证签名,防止伪造通知
  • 必须验证订单号、金额和订单状态
  • 必须在5秒内返回结果
  • 必须能够处理重复通知(检查订单状态是否已处理)

第五部分:测试与上线

5.1 测试环境说明

微信支付没有专门的沙箱环境,所有测试都在真实环境进行,但可以使用0.01元的测试金额。

5.2 测试用例(必须全部覆盖)

  • ✅ 正常支付流程:下单→支付→回调成功→订单状态更新
  • ✅ 用户取消支付:下单→取消支付→订单状态不变
  • ✅ 超时未支付:下单→不支付→超时后关闭订单
  • ✅ 重复支付:同一订单号重复下单(应该返回失败)
  • ✅ 退款流程:支付成功→申请退款→退款成功→订单状态更新
  • ✅ 回调失败重试:故意让回调接口返回错误,验证微信是否会重试
  • ✅ 回调丢失:模拟微信通知丢失,验证前端轮询和后端定时任务是否能正常工作

5.3 上线前最终检查清单

  • [ ] 确认所有配置(支付授权目录、回调地址、API密钥)都是生产环境的
  • [ ] 确认API证书已正确部署到生产服务器
  • [ ] 确认服务器时间与北京时间一致(签名验证依赖时间)
  • [ ] 确认生产环境的域名已正确配置HTTPS
  • [ ] 确认支付超时自动取消订单的定时任务已部署
  • [ ] 确认订单状态查询接口正常工作
  • [ ] 进行1-2笔真实金额的支付测试,确认资金能正常到账

第六部分:异常情况处理

6.1 用户支付成功,但微信回调丢失

  • 解决方案:前端轮询 + 后端定时任务查询微信订单状态
  • 后端可以每天定时查询所有"待支付"且创建时间超过1小时的订单,主动调用微信的"订单查询接口"确认支付状态

6.2 用户重复支付

  • 解决方案:后端保证订单号唯一,同一个订单号只能支付一次
  • 如果用户确实重复支付了,微信会自动退款,或者商家手动退款

6.3 支付超时

  • 解决方案:后端定时任务,每隔几分钟检查一次所有"待支付"订单
  • 如果订单超过支付超时时间,自动将订单状态改为"已取消",并释放锁定的库存

6.4 库存回滚失败

  • 解决方案:记录库存操作日志,定时任务检查不一致的库存数据
  • 对于取消订单和退款订单,必须确保库存正确回滚

6.5 签名错误

  • 解决方案:使用官方SDK,不要自己手写签名
  • 检查APIv3密钥是否正确
  • 检查服务器时间是否与北京时间一致

第七部分:新手必踩坑与避坑指南

  1. 签名错误:90%的签名错误是因为参数排序不对、漏了参数或密钥错误。使用官方SDK可以完全避免这个问题。
  2. 金额单位错误:微信支付的金额单位是,不是元。例如1元要传100,传1会变成0.01元。这是新手最常犯的错误!
  3. 支付授权目录错误:必须精确到最后一个斜杠,且与实际支付页面的目录一致。
  4. 回调地址错误:必须是公网可访问的HTTPS地址,不能有端口(除非是443端口),且不能有重定向和参数。
  5. 没有验证回调签名:这会导致严重的安全漏洞,有人可以伪造支付成功的通知,造成资金损失。
  6. 订单号重复:统一下单接口要求out_trade_no唯一,重复会返回失败。建议使用"日期+随机数"的格式生成订单号。
  7. 证书使用错误:只有退款、撤销订单等敏感接口需要API证书,普通支付接口不需要。
  8. 前端信任本地结果:用户可能会修改前端代码伪造支付成功,必须以后端回调的结果为准。
  9. 没有处理重复通知:微信会多次发送相同的通知,必须检查订单状态是否已处理,避免重复发货。
  10. 回调接口处理时间过长:微信要求回调接口必须在5秒内返回结果,否则会认为通知失败并重试。

第八部分:推荐资源与时间预估

8.1 官方推荐资源

8.2 时间预估

  • 前期准备与账号申请:1-2天(取决于微信审核速度)
  • 商户平台配置:0.5-1天
  • 商品下单流程开发:1-2天
  • 微信支付接口开发:1-2天(使用SDK)
  • 测试与上线:1天

总共大约3-5天就能完成对接。如果遇到问题,优先查阅官方文档或在开发者社区搜索,大部分问题都有现成的解决方案。

附录:核心代码伪代码示例

提交订单接口

java
@Transactional
public OrderVO submitOrder(SubmitOrderRequest request) {
    // 1. 参数校验
    User user = getCurrentUser();
    List<OrderItemRequest> items = request.getItems();
    
    // 2. 库存校验
    for (OrderItemRequest item : items) {
        Product product = productService.getById(item.getProductId());
        if (product == null || !product.isOnSale()) {
            throw new BusinessException("商品不存在或已下架");
        }
        if (product.getStock() < item.getQuantity()) {
            throw new BusinessException("商品库存不足");
        }
    }
    
    // 3. 价格计算
    BigDecimal totalAmount = calculateTotalAmount(items);
    BigDecimal discountAmount = calculateDiscount(request.getCouponId(), totalAmount);
    BigDecimal payAmount = totalAmount.subtract(discountAmount).add(request.getFreight());
    
    // 4. 生成订单号
    String orderNo = generateOrderNo();
    
    // 5. 创建订单
    Order order = new Order();
    order.setOrderNo(orderNo);
    order.setUserId(user.getId());
    order.setTotalAmount(totalAmount);
    order.setDiscountAmount(discountAmount);
    order.setPayAmount(payAmount);
    order.setStatus(OrderStatus.WAIT_PAY);
    order.setCreateTime(new Date());
    order.setExpireTime(DateUtils.addMinutes(new Date(), 30)); // 30分钟超时
    orderService.save(order);
    
    // 6. 创建订单明细
    List<OrderItem> orderItems = new ArrayList<>();
    for (OrderItemRequest item : items) {
        OrderItem orderItem = new OrderItem();
        orderItem.setOrderId(order.getId());
        orderItem.setProductId(item.getProductId());
        orderItem.setSkuId(item.getSkuId());
        orderItem.setProductName(item.getProductName());
        orderItem.setPrice(item.getPrice());
        orderItem.setQuantity(item.getQuantity());
        orderItem.setSubtotal(item.getPrice().multiply(new BigDecimal(item.getQuantity())));
        orderItems.add(orderItem);
    }
    orderItemService.saveBatch(orderItems);
    
    // 7. 预占库存
    for (OrderItemRequest item : items) {
        productService.lockStock(item.getProductId(), item.getQuantity());
    }
    
    // 8. 调用微信统一下单
    WxPayResult payResult = wxPayService.createOrder(orderNo, payAmount, "商品购买", request.getTradeType());
    
    // 9. 返回结果给前端
    OrderVO orderVO = new OrderVO();
    orderVO.setOrderNo(orderNo);
    orderVO.setPayAmount(payAmount);
    orderVO.setPayInfo(payResult);
    
    return orderVO;
}

微信支付回调接口

java
@PostMapping("/wxpay/notify")
public String wxpayNotify(@RequestBody String notifyData, @RequestHeader Map<String, String> headers) {
    try {
        // 1. 验证签名
        if (!wxPayService.verifySignature(notifyData, headers)) {
            log.error("微信支付回调签名验证失败");
            return "{\"code\": \"FAIL\", \"message\": \"签名验证失败\"}";
        }
        
        // 2. 解析回调数据
        WxPayNotifyResult result = wxPayService.parseNotifyResult(notifyData);
        String orderNo = result.getOutTradeNo();
        BigDecimal totalAmount = new BigDecimal(result.getTotal()).divide(new BigDecimal(100));
        String transactionId = result.getTransactionId();
        Date payTime = result.getSuccessTime();
        
        // 3. 验证订单
        Order order = orderService.getByOrderNo(orderNo);
        if (order == null) {
            log.warn("微信支付回调订单不存在:{}", orderNo);
            return "{\"code\": \"SUCCESS\", \"message\": \"订单不存在\"}";
        }
        if (!order.getStatus().equals(OrderStatus.WAIT_PAY)) {
            log.warn("微信支付回调订单已处理:{}", orderNo);
            return "{\"code\": \"SUCCESS\", \"message\": \"订单已处理\"}";
        }
        if (order.getPayAmount().compareTo(totalAmount) != 0) {
            log.error("微信支付回调金额不匹配:订单金额{},支付金额{}", order.getPayAmount(), totalAmount);
            return "{\"code\": \"FAIL\", \"message\": \"金额不匹配\"}";
        }
        
        // 4. 更新订单状态
        order.setStatus(OrderStatus.PAID);
        order.setTransactionId(transactionId);
        order.setPayTime(payTime);
        orderService.updateById(order);
        
        // 5. 扣减库存(从锁定库存转为已售库存)
        List<OrderItem> orderItems = orderItemService.getByOrderId(order.getId());
        for (OrderItem item : orderItems) {
            productService.confirmStock(item.getProductId(), item.getQuantity());
        }
        
        // 6. 发送通知
        smsService.sendPaySuccessNotice(order.getUserId(), orderNo);
        
        log.info("微信支付回调处理成功:{}", orderNo);
        return "{\"code\": \"SUCCESS\", \"message\": \"OK\"}";
    } catch (Exception e) {
        log.error("微信支付回调处理失败", e);
        return "{\"code\": \"FAIL\", \"message\": \"系统错误\"}";
    }
}
/src/technology/dateblog/2026/05/20260530-%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98%E7%BD%91%E7%AB%99%E5%AF%B9%E6%8E%A5%E4%B8%8E%E5%95%86%E5%93%81%E4%B8%8B%E5%8D%95%E5%AE%8C%E6%95%B4%E5%BC%80%E5%8F%91%E6%96%87%E6%A1%A3.html