Wechat アプレット開発演習 11_2 アプレット振込決済と決済通知処理

12.2 ミニプログラム振替決済

アプレットは支払い API (wx.requestPayment) を呼び出して、支払いのために WeChat クライアントをプルアップします。wx.requestPayment インターフェイスのパラメーターは次のように定義されています。

パラメータ名 変数 説明
アプレット ID アプリ ID マーチャントが申請するミニプログラムに対応する appid。注文時に sub_appid が渡された場合、sub_appid の値になる可能性があります。
タイムスタンプ タイムスタンプ The current time. その他の詳細については、「タイムスタンプ ルール」を参照してください。
ランダムな文字列 nonceStr 32 文字以内のランダムな文字列。
注文詳細拡張文字列 パッケージ ミニプログラム注文インターフェースによって返される prepay_id パラメータ値。提出形式は次のとおりです: prepay_id=***
署名方法 サインタイプ 署名タイプ: RSA。
サイン ペイサイン フィールド appId、timeStamp、nonceStr、および package から計算された署名値を使用する署名。

ミニ プログラムが WeChat 支払いを開始するとき、最初にビジネス インターフェイスを呼び出して支払い注文を送信する必要があります。ビジネス インターフェイスは JSAPI を呼び出して支払い注文を出します。呼び出しが成功すると、前払いトランザクション セッション ID (prepay_id) を取得します。次に、ビジネス インターフェイスは、Mini Program. パラメータで要求された支払いを返します。アプレットは、ビジネス インターフェイスから返された支払いパラメータを使用して wx.requestPayment 関数を呼び出し、支払いのために WeChat クライアントをプルアップします。以下は、支払いを開始するためのミニ プログラムのサンプル コードです。

function weixinPay(page, ddid) {
    
    
  var domain = getApp().globalData.domain;
  var url = domain + '/get_pay_param';
  wx.request({
    
    
    url: url,
    data: {
    
    ddid: ddid},
    success: function (res) {
    
    
      if (res.statusCode === 200) {
    
    
        var param = res.data;
        wx.requestPayment({
    
    
          timeStamp: param.TimeStamp,
          nonceStr: param.NonceStr,
          package: param.Package,
          signType: param.SignType,
          paySign: param.PaySign,
          success: function (res) {
    
    
            wx.navigateBack({
    
    });
          },
        });
      }
    }
  });
}

12.3 支払い通知の処理

ユーザーが支払いを完了すると、WeChat は非同期コールバックを介して関連する支払い結果をマーチャントに通知し、マーチャント サーバーはドキュメントの仕様に従って受信処理を実装し、応答を返す必要があります。決済結果通知は加盟店が設定したURLにPOSTメソッドで通知するもので、通知データは暗号化された決済結果を含むJSON形式でエンコードされています。
WeChat が支払い通知を送信すると、通知データに署名し、署名値を HTTP 要求ヘッダーに入れます: Wechatpay-Signature。マーチャントは署名を検証して、要求が WeChat からのものであり、別のサード パーティからのものではないことを確認する必要があります。
コールバック通知を正常に受信した後、マーチャントは 200 または 204 の HTTP 応答コードを返す必要があります。これにより、WeChat 支払いプラットフォームは支払い通知が正常に処理されたと見なします。同じ通知がマーチャント システムに複数回送信される場合があります。マーチャント システムは、重複する通知を適切に処理できなければなりません。推奨される方法は、マーチャント システムが処理のための通知を受信すると、最初に対応するビジネス データのステータスを確認し、通知が処理されたかどうかを判断することです。処理されていない場合は再度処理され、処理されている場合は結果が直接正常に返されます。
支払いプラットフォームが支払い通知を送信するときに、WeChat が受信した応答が仕様を満たしていないかタイムアウトになった場合、WeChat は通知を失敗と見なし、WeChat は特定の戦略を通じて定期的に通知を再開し、成功率を高めます。ただし、WeChat は、通知が最終的に成功することを保証するものではありません。WeChat 支払い通知のパラメーターは次のとおりです。

パラメータ名 変数 説明
通知ID ID 通知の一意の ID
通知の作成時間 create_time 通知が作成された時刻
通知タイプ イベントタイプ 通知の種類、決済成功通知の種類は TRANSACTION.SUCCESS
通知データ型 resource_type 通知のリソース データ型、支払い成功通知は encrypt-resource
+ 通知データ リソース リソース データの通知
コールバックの概要 まとめ コールバックの概要

通知データは次のように定義されます。

パラメータ名 変数 説明
暗号化アルゴリズムの種類 アルゴリズム 開封結果のデータを暗号化するための暗号化アルゴリズムは、現在 AEAD_AES_256_GCM のみをサポートしています。
データ暗号文 暗号文 Base64 でエンコードされた有効化/無効化結果データの暗号文
追加データ 関連データ 追加データ
プリミティブ型 original_type トランザクションである元のコールバック タイプ
ランダムな文字列 ナンス 暗号化に使用するランダム文字列

ciphertext は暗号化されたデータです。APIv3 キー、nonce、および associated_data を使用してデータ暗号文 resource.ciphertext を復号化し、リソース オブジェクトを JSON 形式で取得する必要があります。
決済通知のHTTPレスポンスコードが200または204の場合は正常受信、コールバック処理が異常の場合はレスポンスのHTTPステータスコードが500または4xxとなります。

パラメータ名 変数 説明
戻りステータス コード コード エラー コード、SUCCESS は清算機関が正常に受信されたことを意味し、その他のエラー コードは失敗を意味します。
返されたメッセージ メッセージ 戻り情報が空でない場合は、エラーの原因です。

支払い通知の処理ロジックは次のとおりです。1
) 最初にリクエストのヘッダーから署名情報を取得します
。2) WeChat Pay のプラットフォームの秘密鍵 (加盟店の秘密鍵ではありません) を使用して、署名の検証を実行します。
3) APIv3 キーを使用して支払い注文データを復号化する
まず、支払い通知の関連データ構造を確認します。

type WeixinPayNotice struct {
    
    
   //通知的唯一ID
   ReqId             string              `json:"id"`
   //通知创建的时间
   CreateTime      string              `json:"create_time"`
   //通知的类型,支付成功通知的类型为TRANSACTION.SUCCESS
   Event_type        string              `json:"event_type"`
   //通知的资源数据类型,支付成功通知为encrypt-resource
   ResourceType   string           `json:"resource_type"`
   //回调摘要
   Summary         string              `json:"summary"`
   //通知资源数据
   Resource         NoticeResource    `json:"resource"`
}
type NoticeResource struct {
    
    
   //对开启结果数据进行加密的加密算法
   Algorithm      string           `json:"algorithm"`
   //数据密文
   Ciphertext     string           `json:"ciphertext"`
   //附加数据
   AssociatedData string           `json:"associated_data"`
   //原始回调类型,为transaction
   original_type  string           `json:"original_type"`
   //加密使用的随机串
   Nonce          string           `json:"nonce"`
}
//支付通知返回数据结构
type WxPayNotifyRet struct {
    
    
   Return_code string `json:"code"`
   Return_msg  string `json:"message"`
}
//支付通知返回
func HttpCallBackReturn(w http.ResponseWriter, status int, code string, message string)  {
    
    
   var ent WxPayNotifyRet
   ent.Return_code = code
   ent.Return_msg = message
   data, _ := json.Marshal(ent)
   w.WriteHeader(status)
   w.Write(data)
}

支払い通知を送信するとき、WeChat Pay は、直接接続された加盟店モデルとサービス プロバイダー モデルに異なるデータ構造を提供します. このペーパーでは、直接接続された加盟店モデルとサービス プロバイダー モデルは一連のデータ構造を共有し、 JSON の omitempty タグを介して 2 つのモードの違い。以下は、データ構造の定義です。

//微信支付订单信息
type WxPayInfo struct {
    
    
   //应用ID(普通商户)
   Appid             string `json:"appid"`
   //服务商户号(普通商户)
   Mchid                 string `json:"mchid"`
   //服务商用ID(服务商)
   Sp_appid              string `json:"sp_appid"`
   //服务商户号(服务商)
   Sp_mchid           string `json:"sp_mchid"`
   //子商户用ID(服务商)
   Sub_appid          string `json:"sub_appid"`
   //子商户的商户号(服务商)
   Sub_mchid          string `json:"sub_mchid"`
   //商户系统内部订单号
   Out_trade_no       string `json:"out_trade_no"`
   //微信支付订单号
   Transaction_id         string `json:"transaction_id"`
   //交易类型,枚举值:JSAPI
   Trade_type            string `json:"trade_type"`
   //交易状态,SUCCESS:支付成功 REFUND:转入退款 NOTPAY:未支付 CLOSED:已关闭 PAYERROR:支付失败
   Trade_state        string `json:"trade_state"`
   //交易状态描述
   Trade_state_desc    string `json:"trade_state_desc"`
   //付款银行
   Bank_type         string `json:"bank_type"`
   //附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用
   Attach                string `json:"attach"`
   //支付完成时间
   Success_time           string `json:"success_time"`
   //订单金额信息
   Amount        OrderAmount    `json:"amount"`
   //支付者信息
   Payer     OrderPayer        `json:"payer"`
}

支払い通知を処理するサンプル コードを見てみましょう。

func HandlerCallBackV3(w http.ResponseWriter, r *http.Request) {
    
    
   body, err := ioutil.ReadAll(r.Body)
   if err != nil {
    
    
      wxpay.WxPayCallBackReturn(w, "FAIL", "FAIL")
      return
   }
   if len(body) < 1 {
    
    
      err := fmt.Errorf("读取http body失败")
      wxpay.WxPayCallBackReturn(w, "FAIL", "FAIL")
      return
   }

   //读取签名验证所需的参数
   var sing_param WxSignParam
   err = sing_param.InitFromRequest(r, string(body))
   if err != nil {
    
    
      wxpay.WxPayCallBackReturn(w, "FAIL", "FAIL")
      return
   }

   //获取平台证书,并进行签名验证
   plat_certificate := GetPlatCertificate(ent, sing_param.CertSerial)
   err = ResponseValidate(&sing_param, plat_certificate);
   if err != nil {
    
    
      wxpay.WxPayCallBackReturn(w, "FAIL", "FAIL")
      return
   }

   //body数据解析
   var ent_cb WeixinPayNotice
   if err = json.Unmarshal(body, &ent_cb); err != nil {
    
    
      wxpay.WxPayCallBackReturn(w, "FAIL", "FAIL")
      return
   }

   //数据解密
   decryptBytes, err := DecryptAES256GCM(
      ent.MchAPIKey,
      ent_cb.Resource.AssociatedData,
      ent_cb.Resource.Nonce,
      ent_cb.Resource.Ciphertext)
   if err != nil {
    
    
      wxpay.WxPayCallBackReturn(w, "FAIL", "FAIL")
      return
   }

   //支付订单数据解析
     var pay_info WxPayInfo
   err = json.Unmarshal([]byte(decryptBytes), &pay_info)
   if err != nil {
    
    
      wxpay.WxPayCallBackReturn(w, "FAIL", "FAIL")
      return
   }
   //其他业务逻辑开始
   //..........................
   //其他业务逻辑结束
wxpay.WxPayCallBackReturn(w, "SUCCESS", "SUCCESS")
}

おすすめ

転載: blog.csdn.net/gz_hm/article/details/128510392