Оплата скан-кодом для оплаты nodejs WeChat

Node.js WeChat Egg.js

предисловие

В этой статье в основном описаны проблемы, с которыми я столкнулся в процессе оплаты скан-кодом WeChat, и дана ссылка. Надеюсь, она будет вам полезна. Если есть какие-либо ошибки, пожалуйста, исправьте меня.

среда разработки

  • nodejs v8.1.0
  • egg v1.1.0

Готов к работе

  • WeChat общедоступный аккаунт-приложение
  • Идентификатор продавца WeChat-mch_id
  • значение ключа (требуется алгоритмом подписи, на самом деле это 32-битный пароль, который можно сгенерировать с помощью md5) (путь настройки ключа: торговая платформа WeChat (pay.weixin.qq.com) --> настройки учетной записи --> Безопасность API- -> Настройки ключа)

Оплата скан-кодом - единый порядок

Ниже приведен режим WeChat 2, поскольку он относительно прост.

let MD5 = require('md5'),
    xml2js = require('xml2js'),
    url = "https://api.mch.weixin.qq.com/pay/unifiedorder",// 下单请求地址
    appid = '公众号id',
    mch_id = '微信商户号';
    notify_url = '回调地址',
    out_trade_no = '自己设置的订单号',// 微信会有自己订单号、我们自己的系统需要设置自己的订单号
    total_fee = '订单金额',// 注意,单位为分
    body = '商品简单描述', 
    trade_type = 'NATIVE',// 交易类型,JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付
    nonce_str = moment().format('YYYYMMDDHHmmssSSS'),// 随机字符串32位以下
    stringA = `appid=${公众号id}&body=${body}&mch_id=${微信商户号}&nonce_str=${nonce_str}&notify_url=${
    notify_url}&out_trade_no=${out_trade_no}&spbill_create_ip=${ctx.request.ip}&total_fee=${total_fee}&trade_type=${trade_type}`,
    stringSignTemp = stringA + "&key=xxxxxxxxxxxxxxxxx", //注:key为商户平台设置的密钥key
    sign = MD5(stringSignTemp).toUpperCase();  //注:MD5签名方式

Вот некоторые из параметров, которые нам нужны

Посмотреть алгоритм генерации подписиофициальный сайт WeChat

spbill_create_ip — IP-адрес терминала.

Следующее объединяет все параметры в xml

let formData = "<xml>";
formData += "<appid>" + appid + "</appid>"; //appid
formData += "<body>" + body + "</body>"; //商品或支付单简要描述
formData += "<mch_id>" + mch_id + "</mch_id>"; //商户号
formData += "<nonce_str>" + nonce_str + "</nonce_str>"; //随机字符串,不长于32位
formData += "<notify_url>" + notify_url + "</notify_url>"; //支付成功后微信服务器通过POST请求通知这个地址
formData += "<out_trade_no>" + out_trade_no + "</out_trade_no>"; //订单号
formData += "<total_fee>" + total_fee + "</total_fee>"; //金额
formData += "<spbill_create_ip>" + ctx.request.ip + "</spbill_create_ip>"; //ip
formData += "<trade_type>NATIVE</trade_type>"; //NATIVE会返回code_url ,JSAPI不会返回
formData += "<sign>" + sign + "</sign>";
formData += "</xml>";
// 这里使用了egg里面请求的方式
const resultData = yield ctx.curl(url, {
  method: "POST",
  content: formData,
  headers: {
    "content-type": "text/html",
  },
});

// xml转json格式
xml2js.parseString(resultData.data, function (err, json) {
  if (err) {
    new Error("解析xml报错");
  } else {
    var result = formMessage(json.xml); // 转换成正常的json 数据
    console.log(result); //打印出返回的结果
  }
});
var formMessage = function (result) {
  var message = {};
  if (typeof result === "object") {
    var keys = Object.keys(result);
    for (var i = 0; i < keys.length; i++) {
      var item = result[keys[i]];
      var key = keys[i];
      if (!(item instanceof Array) || item.length === 0) {
        continue;
      }
      if (item.length === 1) {
        var val = item[0];
        if (typeof val === "object") {
          message[key] = formMessage(val);
        } else {
          message[key] = (val || "").trim();
        }
      } else {
        message[key] = [];
        for (var j = 0, k = item.length; j < k; j++) {
          message[key].push(formMessage(itemp[j]));
        }
      }
    }
  }
  return message;
};

Метод запроса яйца используется выше, и узел может использовать запрос или аксиомы.

var request = require('request');
request({
  url: url,
  method: "POST",
  body: formData
}, function(error, response, body) {
  if (!error && response.statusCode == 200) {
  }
}); 

Если запрос будет успешным, он в конечном итоге вернет xml, а затем мы проанализируем его в формате json, будетcode_urlа такжеout_trade_no, нам нужно вернуть эти два во внешний интерфейс, а затем показать пользователю, чтобы он отсканировал код, сгенерировав QR-код для завершения платежа.

Отслеживайте успешность платежа

После того, как вышеуказанная операция завершена, нам нужно знать, завершил ли пользователь платеж, поскольку пользователь останется на этой странице, нам нужно уведомить пользователя об успешном платеже после того, как пользователь оплатил. Прежде всего, когда пользователь инициирует платеж, мы сгенерируем QR-код, чтобы пользователь мог завершить платеж, отсканировав код.Что нам нужно сделать, так это запустить таймер и отправлять запрос через равные промежутки времени.В это время , наш фон узла должен написать интерфейс для запроса заказов, мы получили его раньшеout_trade_no, который является номером заказа внутри нашей системы.Мы отправляем эти данные в интерфейс для запроса заказов в фоновом режиме, а затем фон будет запрашивать адрес интерфейса запроса WeChat после его получения.https://api.mch.weixin.qq.com/pay/orderquery, процесс такой же, как и выше, но адрес интерфейса отличается от xml, возвращаемого WeChat, а возвращаемое поле будет иметь статус, которыйSUCCESSа такжеNOTPAY, мы можем вернуться к внешнему интерфейсу, оценив, был ли платеж успешным, и после успеха сообщить пользователю, что платеж прошел успешно, и закрыть таймер.

адрес обратного вызова

Это очень важная часть.Большинство операций можно выполнить на вышеперечисленном, но бывают и частные случаи, например компьютер пользователя отключен от интернета и не может отправить запрос, но мобильный телефон оплачен, что вызовет нам не записывать платежную информацию пользователя. На этот раз адрес обратного вызова очень важен

Установить адрес обратного вызова

WeChat Merchant Center->Центр продуктов->Конфигурация разработки->Сканировать код платежа

Тогда что нам нужно сделать, это использовать бэкэндpostдля получения информации об асинхронном обратном вызове, отправленной WeChat, а такжеxmlФормат, обратите внимание, что если получение xml не поддерживается, вы можете получить пустые данные Здесь также следует отметить, что когда мы сохраняем платежную информацию пользователя, мы должны сначала проверить, оплачен ли заказ, чтобы избежать повторных операций, и может быть вставлено несколько записей.

Суммировать

Ямы для оплаты скан-кода WeChat все еще существуют.Если вы исследуете в первый раз, необходимо обратить внимание на следующие моменты.

  1. Алгоритм подписи должен писать правильно, в противном случае он не удастся, чтобы поставить его правильно
  2. Wechat возвращает данные в формате xml, нам приходится конвертировать их в json через плагин, чтобы было удобно получать данные
  3. вернутьcode_urlЧтобы сгенерировать QR-код для фронтенда, вам нужно открыть таймер, чтобы проверить, был ли оплачен заказ, и, наконец, уведомить пользователя о результате
  4. Адрес обратного вызова очень важен, нашему бэкэнду нужноpostПолучите информацию обратного вызова, возвращенную WeChat, а затем сохраните информацию, но перед сохранением платежной информации пользователя нам нужно знать, был ли сохранен заказ, чтобы избежать повторных добавлений. Кроме того, возвращаются xml-данные, и бэкенд должен убедиться, что их можно получить, их невозможно получить обычным способом, и требуются дополнительные настройки.

Адрес статьиОплата скан-кодом для оплаты nodejs WeChat

Адрес личного блогаwww.wclimb.site

Адрес GitHubwclimb

пс: недавно ищу работу, беру на себя смелость спросить есть ли рекруты.