微信支付集成_JSAPI

微信支付集成_JSAPI

0.背景

产品接入微信支付,需要实现PC端扫码支付,移动端公众号支付,以及小程序支付.经过调研统一采用微信的JSAPI实现.主要过程分两个大步骤:

  • 下单接口(/v3/pay/transactions/jsapi),获取预付单号
  • 切换到微信环境(公众号,小程序)并结合预付单号,唤起支付界面,用户完成支付

需要实际在手机完成支付,本次测试代码全部通过前端实现.针对访问微信下单接口,通过ngin代理避免前端跨域问题. 有完整测试代码,若需要请关注公众号小满小慢 回复wepay 获取.获取代码后,你只需把src部署到你服务器,然后在微信中访问 即可.如果域名能映射到你本地开发机上,直接npm run server运行也是不错的选择. 这种方式运行,已经内置代理.不需要单独再配置nginx

1.集成前置准备

需要在微信支付平台申请商户号.申请好以后需要在商户号上关联对应的公众号,小程序等.涉及微信支付平台,需要提前准备一下信息

  • 微信支付地址: api.mch.weixin.qq.com
  • 商户号ID (mchid)
  • 商户API证书 (apiclient_key.pem)
  • 商户API证书序列号(merchant_serial_no)
  • 公众号或小程序的appid (appid)
  • 测试用户对应公众或小程序的openid (openid)

系统集成需要准备以下信息

  • 备案通过的域名
  • 微信支付回调地址 (notify_url)

商户平台配置

  • 产品中心/AppID账号管理 关联小程序或者公众号
  • 产品中心/开发配置 注册唤起支付url必须一样

2. 测试页面开发

测试页面方便不同的商户号测试,整体分两部分内容

  1. 全局配置,主要配置 mchid,apiclient_key.pem,merchant_serial_no,appid,openid,notify_url 配置好以后,信息存储在localStorage中
  2. 支付信息,主要设置 支付金额, 支付说明,是否分账.支付金额最多两位小数

整体测试页面如下

3. JSAPI下单接口

支付接口需要做签名处理,签名采用RAS算法,使用forge.js提供的算法

官方参考文档 https://pay.weixin.qq.com/doc/v3/merchant/4012791856

下单接口的签名串规则如下:

txt 复制代码
HTTP请求方法\n
URL\n
请求时间戳\n
请求随机串\n
请求报文主体\n

实际代码体现如下:

javascript 复制代码
const message =
  "POST\n" +
  "/v3/pay/transactions/jsapi\n" +
  timeStamp + "\n" +
  nonceStr +"\n" +
  JSON.stringify(payData) +"\n";

在前端针对timeStamp有些特殊处理

  • 参数要求到秒,前端通过new Date().getTime()是到毫秒的,需要除1000
  • 必须转换成字符串,否则微信接口会报错

生成签名的主要代码如下:

javascript 复制代码
// 小游戏 地心侠士
function getSign(message, privateKeyStr) {
  const privateKey = forge.pki.privateKeyFromPem(privateKeyStr);
  const sha256 = forge.md.sha256.create();
  sha256.update(forge.util.encodeUtf8(message));
  const signature = forge.util.encode64(privateKey.sign(sha256));
  return signature
}

最终完整的认证信息如下:

javascript 复制代码
WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",serial_no="${serialNo}",nonce_str="${nonceStr}",timestamp="${timeStamp}",signature="${signature}"

前端完整下单代码如下:

javascript 复制代码
async function processPayinfo(cfgInfo, payInfo) {
  const payData =
  {
      "appid": cfgInfo.appid,
      "mchid": cfgInfo.mchid,
      "description": payInfo.description,
      "out_trade_no": payInfo.out_trade_no || new Date().getTime() + "",
      "attach": payInfo.attach,
      "notify_url": cfgInfo.callback_url,
      "support_fapiao": false,
      "amount": {
          "total": Math.round(payInfo.amount * 100),
          "currency": "CNY"
      },
      "payer": {
          "openid": cfgInfo.openid
      },
      "settle_info": {
          "profit_sharing": payInfo.split_payment
      }
  };
  const nonceStr = generateNonceStr();
  const timeStamp = getTimeStamp();
  const mchid = cfgInfo.mchid;
  const method = "POST";
  const payUri = "/v3/pay/transactions/jsapi";
  // 小游戏 地形侠士 签名原始串
  const message =method +"\n" +payUri +"\n" +timeStamp +
                "\n" +nonceStr +"\n" +JSON.stringify(payData) +"\n";
  // 小游戏 地心侠士 生成签名    
  const serialNo = cfgInfo.merchant_serial_no
  const privateKeyStr = cfgInfo.apiclient_key;
  const signature = getSign(message, privateKeyStr);
  // 小游戏 地心侠士 完整认证串
  let auth = `WECHATPAY2-SHA256-RSA2048 mchid="${mchid}",serial_no="${serialNo}",nonce_str="${nonceStr}",timestamp="${timeStamp}",signature="${signature}`
  const response = await fetch(payUri, {
      method: method,
      mode: 'cors',
      headers: {
          'Content-Type': 'application/json',
          'Authorization': auth
      },
      body: JSON.stringify(payData)
  });
  if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
  }
  const result = await response.json();
  console.log(result)
  return result;
}

以上代码,执行成功就会返回预付订单号,类似如下的响应正文

json 复制代码
{
    "prepay_id": "wx132023572988633421178322a067e20000"
}

4. 唤起微信支付

在上边拿到预付单号以后,就可以在微信环境唤起微信支付界面了.唤起微信支付通用涉及到签名,这里的签名方法一样,但是签名串规则略有变化.签名串规则如下:

text 复制代码
appId\n
时间戳\n
随机字符串\n
prepay_id=\n

这需要注意的是,package并不是下单接口返回的JSON串,需要转换成key=value的形式 完成唤起支付代码如下:

javascript 复制代码
function onBridgeReady(cfgInfo, prepayinfo, cb) {
  const nonceStr = generateNonceStr();
  const timeStamp = getTimeStamp();
  // 小游戏 地心侠士 转换预付单号
  const package = "prepay_id=" + prepayinfo.prepay_id;
  const message =cfgInfo.appid +"\n" +timeStamp +"\n" +
                 nonceStr +"\n" + package +"\n";
  // 小游戏 地心侠士 生成签名   
  const privateKeyStr = cfgInfo.apiclient_key;
  const signature = getSign(message, privateKeyStr);
  WeixinJSBridge.invoke('getBrandWCPayRequest', {
      "appId": cfgInfo.appid,
      "timeStamp": timeStamp,
      "nonceStr": nonceStr,
      "package": package,
      "signType": "RSA",
      "paySign": signature,
  }, function (res) {
      cb && cb(res);
      if (res.err_msg == "get_brand_wcpay_request:ok") {
          console.log("支付成功")
      }
  });
}

运行成功后,就会弹出微信支付的页面,测试界面显示如下

5. nginx跨域配置

整个测试代码完全通过前端JS实现,在访问微信下单接口时会有跨域限制,在实际服务器中,需要通过nginx对微信接口实现代理.关键配置如下

nigx 复制代码
# === 小游戏 地心侠士 微信支付代理配置 ===
location ^~ /v3/pay/ {
  # 目标服务器地址(替换为实际地址)
  proxy_pass https://api.mch.weixin.qq.com;
  
  # 关键头设置
  proxy_set_header Host api.mch.weixin.qq.com;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header User-Agent "WeChat-Pay-Proxy/1.0";
  
  # 超时设置
  proxy_connect_timeout 30s;
  proxy_send_timeout 30s;
  proxy_read_timeout 30s;
  
  # 处理CORS
  add_header 'Access-Control-Allow-Origin' '*' always;
  add_header 'Access-Control-Allow-Methods' '*' always;
  add_header 'Access-Control-Allow-Headers' '*' always;
  
  if ($request_method = 'OPTIONS') {
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' '*';
      add_header 'Access-Control-Allow-Headers' '*';
      return 204;
  }
}

6. 总结

微信交互常规的做法是通过后端发送请求到微信服务器,微信服务器返回数据,然后通过前端获取数据,再进行交互。在测试时,前端唤起支付,后端提供预定单接口.前后端都不方便测试支付情况.所有才结合微信提供POSTMAN中接口测试方法,完成这个纯前端的,通用的,微信支付测试页面.如需要完成源码,请在微信公众小满小慢 回复wepay 获取测试代码 原文地址:mp.weixin.qq.com/s/r8kAPXyuW...

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
爱敲代码的小鱼6 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax