视频一区二区三区自拍_千金肉奴隷1985未删减版在线观看_国产成人黄色视频在线播放_少女免费播放片高清在线观看_国产精品v欧美精品v

基礎(chǔ)支付
JSAPI支付
APP支付
H5支付
Native支付
小程序支付
合單支付
付款碼支付
經(jīng)營能力
微信支付分
支付即服務(wù)
行業(yè)方案
智慧商圈
微信支付分停車服務(wù)
電子發(fā)票
營銷工具
代金券
商家券
委托營銷
支付有禮
小程序發(fā)券插件
H5發(fā)券
圖片上傳(營銷專用)
現(xiàn)金紅包
資金應(yīng)用
商家轉(zhuǎn)賬到零錢
分賬
風(fēng)險(xiǎn)合規(guī)
消費(fèi)者投訴2.0
其他能力
清關(guān)報(bào)關(guān)
圖片上傳
視頻上傳
微信支付平臺(tái)證書

APP支付開發(fā)指引

1. 接口規(guī)則

為了在保證支付安全的前提下,帶給商戶簡單、一致且易用的開發(fā)體驗(yàn),我們推出了全新的微信支付APIv3接口。該版本API的具體規(guī)則請參考“APIv3接口規(guī)則
備注:當(dāng)前接口用于微信國內(nèi)錢包

2. 開發(fā)準(zhǔn)備

2.1. 搭建和配置開發(fā)環(huán)境

為了幫助開發(fā)者調(diào)用開放接口,我們提供了JAVA、PHP、GO三種語言版本的開發(fā)庫,封裝了簽名生成、簽名驗(yàn)證、敏感信息加/解密、媒體文件上傳等基礎(chǔ)功能(更多語言版本的開發(fā)庫將在近期陸續(xù)提供

測試步驟

1、根據(jù)自身開發(fā)語言,選擇對(duì)應(yīng)的開發(fā)庫并構(gòu)建項(xiàng)目,具體配置請參考下面鏈接的詳細(xì)說明:

    ? wechatpay-java(推薦)wechatpay-apache-httpclient,適用于Java開發(fā)者。

    ? wechatpay-php(推薦)、wechatpay-guzzle-middleware,適用于PHP開發(fā)者

    注:當(dāng)前開發(fā)指引接口PHP示例代碼采用wechatpay-guzzle-middleware版本

    ? wechatpay-go,適用于Go開發(fā)者

更多資源可前往微信支付開發(fā)者社區(qū)搜索查看

2、創(chuàng)建加載商戶私鑰、加載平臺(tái)證書、初始化httpClient的通用方法


@Before
public void setup() throws IOException {
    // 加載商戶私鑰(privateKey:私鑰字符串)
    PrivateKey merchantPrivateKey = PemUtil
            .loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
 
    // 加載平臺(tái)證書(mchId:商戶號(hào),mchSerialNo:商戶證書序列號(hào),apiV3Key:V3密鑰)
    AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
            new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)),apiV3Key.getBytes("utf-8"));
 
    // 初始化httpClient
    httpClient = WechatPayHttpClientBuilder.create()
            .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
            .withValidator(new WechatPay2Validator(verifier)).build();
}
 
@After
public void after() throws IOException {
    httpClient.close();
}

use GuzzleHttp\Exception\RequestException;
use WechatPay\GuzzleMiddleware\WechatPayMiddleware;
use WechatPay\GuzzleMiddleware\Util\PemUtil;
use GuzzleHttp\HandlerStack;
 
// 商戶相關(guān)配置,
$merchantId = '1000100'; // 商戶號(hào)
$merchantSerialNumber = 'XXXXXXXXXX'; // 商戶API證書序列號(hào)
$merchantPrivateKey = PemUtil::loadPrivateKey('./path/to/mch/private/key.pem'); // 商戶私鑰文件路徑
 
// 微信支付平臺(tái)配置
$wechatpayCertificate = PemUtil::loadCertificate('./path/to/wechatpay/cert.pem'); // 微信支付平臺(tái)證書文件路徑
 
// 構(gòu)造一個(gè)WechatPayMiddleware
$wechatpayMiddleware = WechatPayMiddleware::builder()
    ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey) // 傳入商戶相關(guān)配置
    ->withWechatPay([ $wechatpayCertificate ]) // 可傳入多個(gè)微信支付平臺(tái)證書,參數(shù)類型為array
    ->build();
 
// 將WechatPayMiddleware添加到Guzzle的HandlerStack中
$stack = GuzzleHttp\HandlerStack::create();
$stack->push($wechatpayMiddleware, 'wechatpay');
 
// 創(chuàng)建Guzzle HTTP Client時(shí),將HandlerStack傳入,接下來,正常使用Guzzle發(fā)起API請求,WechatPayMiddleware會(huì)自動(dòng)地處理簽名和驗(yàn)簽
$client = new GuzzleHttp\Client(['handler' => $stack]);

/*
    Package core 微信支付api v3 go http-client 基礎(chǔ)庫,你可以使用它來創(chuàng)建一個(gè)client,并向微信支付發(fā)送http請求
    只需要你在初始化客戶端的時(shí)候,傳遞credential以及validator
    credential用來生成http header中的authorization信息
    validator則用來校驗(yàn)回包是否被篡改
    如果http請求返回的err為nil,一般response.Body 都不為空,你可以嘗試對(duì)其進(jìn)行序列化
    請注意及時(shí)關(guān)閉response.Body
    注意:使用微信支付apiv3 go庫需要引入相關(guān)的包,該示例代碼必須引入的包名有以下信息

    "context"
    "crypto/x509"
    "fmt"
    "io/ioutil"
    "log"
    "github.com/wechatpay-apiv3/wechatpay-go/core"
    "github.com/wechatpay-apiv3/wechatpay-go/core/option"
    "github.com/wechatpay-apiv3/wechatpay-go/utils"

    */
func SetUp() (opt []option.ClientOption, err error) {
    //商戶號(hào)
    mchID := ""
    //商戶證書序列號(hào)
    mchCertSerialNumber := ""
    //商戶私鑰文件路徑
    privateKeyPath := ""
    //平臺(tái)證書文件路徑
    wechatCertificatePath := ""

    // 加載商戶私鑰
    privateKey, err := utils.LoadPrivateKeyWithPath(privateKeyPath)
    if err != nil {
        log.Printf("load private err:%s", err.Error())
        return nil, err
    }
    // 加載微信支付平臺(tái)證書
    wechatPayCertificate, err := utils.LoadCertificateWithPath(wechatCertificatePath)
    if err != nil {
        log.Printf("load certificate err:%s",err)
        return nil, err
    }
    //設(shè)置header頭中authorization信息
    opts := []option.ClientOption{
        option.WithMerchant(mchID, mchCertSerialNumber, privateKey), // 設(shè)置商戶相關(guān)配置
        option.WithWechatPay([]*x509.Certificate{wechatPayCertificate}), // 設(shè)置微信支付平臺(tái)證書,用于校驗(yàn)回包信息用
    }
    return opts, nil
}

3、基于接口的示例代碼,替換請求參數(shù)后可發(fā)起測試

說明:

? 上面的開發(fā)庫為微信支付官方開發(fā)庫,其它沒有審核或者控制下的第三方工具和庫,微信支付不保證它們的安全性和可靠性

通過包管理工具引入SDK后,可根據(jù)下面每個(gè)接口的示例代碼替換相關(guān)參數(shù)后進(jìn)行快速測試

? 開發(fā)者如果想詳細(xì)了解簽名生成、簽名驗(yàn)證、敏感信息加/解密、媒體文件上傳等常用方法的具體代碼實(shí)現(xiàn),可閱讀下面的詳細(xì)說明:

    1.簽名生成

    2.簽名驗(yàn)證

    3.敏感信息加解密

    4.merchantPrivateKey(私鑰)

    5.wechatpayCertificates(平臺(tái)證書)

    6.APIV3Key(V3 key)

? 如想更詳細(xì)的了解我們的接口規(guī)則,可查看我們的接口規(guī)則指引文檔

2.2. 業(yè)務(wù)開發(fā)配置

2.2.1. 注冊APP

APP接入微信支付,需要先將商戶APP在微信開放平臺(tái)進(jìn)行注冊,登記APP開發(fā)參數(shù)以生成APPID。具體操作步驟如下:

一、登錄微信開放平臺(tái),進(jìn)入【管理中心 → 移動(dòng)應(yīng)用 → 創(chuàng)建移動(dòng)應(yīng)用】;

二、完成基本信息的錄入,商戶需要在本步驟提交APP對(duì)應(yīng)的下載地址,應(yīng)用官網(wǎng),應(yīng)用水印,icon等業(yè)務(wù)信息;

三、完成平臺(tái)信息的錄入,商戶需要在本步驟提交APP在Android及iOS端對(duì)應(yīng)的開發(fā)參數(shù),包括Android端應(yīng)用的包名,應(yīng)用簽名,iOS端應(yīng)用的bundle ID, universal link等;

注意:

四、以上信息全部提交完成后,即完成APP的注冊,商戶可在【管理中心 → 移動(dòng)應(yīng)用】中,選擇具體的應(yīng)用查看其APPID及已獲得的接口能力;

五、獲取到APP的APPID后,需要將該APPID與商戶的收款mch_id進(jìn)行綁定,商戶可登錄商戶平臺(tái)后前往【產(chǎn)品中心 -> AppID賬號(hào)管理】界面中進(jìn)行AppID的綁定及管理,界面如圖所示:

2.2.2. iOS開發(fā)要點(diǎn)說明
? iOS系統(tǒng)OpenSDK升級(jí)指引

由于蘋果公司在iOS13系統(tǒng)回收了查詢 App bundleID 的能力,導(dǎo)致微信無法保證授權(quán)憑證能正確返回給AppID對(duì)應(yīng)的應(yīng)用。為此,微信支付強(qiáng)烈要求所有商戶盡快升級(jí)到OpenSDK1.8.6,并讓用戶及時(shí)更新APP,否則安全風(fēng)險(xiǎn)將一直存在。謝謝配合!

詳細(xì)OpenSDK升級(jí)指引請參見:OpenSDK升級(jí)指引

注意:OpenSDK升級(jí)后請一定按照文檔要求完成驗(yàn)證工作,確保OpenSDK升級(jí)成功。

? 開發(fā)配置:

以下項(xiàng)目開發(fā)環(huán)境以Xcode6.0,運(yùn)行環(huán)境為IOS7.0為例,說明其開發(fā)中需要的操作

  • 一、項(xiàng)目設(shè)置APPID

    商戶在微信開放平臺(tái)申請開發(fā)APP應(yīng)用后,微信開放平臺(tái)會(huì)生成APP的唯一標(biāo)識(shí)APPID。在Xcode中打開項(xiàng)目,設(shè)置項(xiàng)目屬性中的URL Schemes為您的APPID。如圖標(biāo)紅位置所示

  • 二、注冊APPID

    商戶APP工程中引入微信lib庫和頭文件,調(diào)用API前,需要先向微信注冊您的APPID,代碼如下:

    [WXApi registerApp:@"wxd930ea5d5a258f4f" withDescription:@"demo 2.0"];

?注意:

OpenSDK前端拉起支付及SDK回調(diào)的相關(guān)說明,請參考OpenSDK調(diào)起支付說明

  • 一、后臺(tái)設(shè)置

    商戶在微信開放平臺(tái)申請開發(fā)應(yīng)用后,微信開放平臺(tái)會(huì)生成APP的唯一標(biāo)識(shí)APPID。由于需要保證支付安全,需要在開放平臺(tái)綁定商戶應(yīng)用包名和應(yīng)用簽名,設(shè)置好后才能正常發(fā)起支付。設(shè)置界面在【開放平臺(tái)】中的欄目【管理中心 / 修改應(yīng)用 / 修改開發(fā)信息】里面,如圖紅框內(nèi)所示。

    應(yīng)用包名:是在APP項(xiàng)目配置文件AndroidManifest.xml中聲明的package值,例如上圖中的package="demo.wxpay.tenpay.com"。

    應(yīng)用簽名:根據(jù)項(xiàng)目的應(yīng)用包名和編譯使用的keystore,可由簽名工具生成一個(gè)32位的md5串,在調(diào)試的手機(jī)上安裝簽名工具后,運(yùn)行可生成應(yīng)用簽名串,如圖8.9所示,綠色串即應(yīng)用簽名。

    點(diǎn)擊下載簽名生成工具

  • 二、注冊APPID

    商戶APP工程中引入微信JAR包,調(diào)用API前,需要先向微信注冊您的APPID,代碼如下:

    final IWXAPI msgApi = WXAPIFactory.createWXAPI(context, null);

    // 將該app注冊到微信

    msgApi.registerApp("wxd930ea5d5a258f4f");


?注意:

OpenSDK前端拉起支付及SDK回調(diào)的相關(guān)說明,OpenSDK調(diào)起支付說明

3. 快速接入

3.1. 業(yè)務(wù)流程圖

重點(diǎn)步驟說明:

步驟3:用戶下單發(fā)起支付,商戶可通過微信支付APP下單API創(chuàng)建支付訂單。

商戶調(diào)用APP下單API后,分正常返回和異常返回情況:

  • 正常返回:返回prepay_id,商戶可根據(jù)返回的prepay_id來生成調(diào)用OpenSDK的簽名以執(zhí)行下一步。
  • 異常返回:返回http code或錯(cuò)誤碼,商戶可根據(jù)http code列表錯(cuò)誤碼說明來排查原因并執(zhí)行下一步操作

步驟8: 商戶通過APP調(diào)起支付OpenSDK調(diào)起微信支付,發(fā)起支付請求,有關(guān)OpenSDK調(diào)起支付的詳細(xì)說明,請參考2.2.2部分的說明

步驟15-19 : 用戶支付成功后,商戶可通過以下兩種方式獲取訂單狀態(tài)

我們通過以下接口將用戶確認(rèn)訂單信息回調(diào)通知給商戶系統(tǒng):

方法一:支付結(jié)果通知。用戶支付成功后,微信支付會(huì)將支付成功的結(jié)果以回調(diào)通知的形式同步給商戶,商戶的回調(diào)地址需要在調(diào)用APP下單API時(shí)傳入notify_url參數(shù)。

方法二:當(dāng)因網(wǎng)絡(luò)抖動(dòng)或本身notify_url存在問題等原因,導(dǎo)致無法接收到回調(diào)通知時(shí),商戶也可主動(dòng)調(diào)用查詢訂單API 查詢訂單API來獲取訂單狀態(tài)


3.2. API接入(含示例代碼)

本文檔展示了如何使用微信支付服務(wù)端 SDK 快速接入APP支付產(chǎn)品,完成與微信支付對(duì)接的部分。

注意:

  • 文檔中的代碼示例是用來闡述 API 基本使用方法,代碼中的示例參數(shù)需替換成商戶自己賬號(hào)及參數(shù)才能跑通。
  • 以下接入步驟僅提供參考,請商戶結(jié)合自身業(yè)務(wù)需求進(jìn)行評(píng)估、修改。
3.2.1. 【服務(wù)端】APP下單

步驟說明:用戶在商戶APP內(nèi)完成商戶選擇后進(jìn)入支付頁面,商戶需要通過后端請求該APP下單API來獲取預(yù)支付ID。

示例代碼

public void CreateOrder() throws Exception{
  //請求URL
  HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/app");
  // 請求body參數(shù)
  String reqdata = "{"
          + "\"time_expire\":\"2018-06-08T10:34:56+08:00\","
          + "\"amount\": {"
          + "\"total\":100,"
          + "\"currency\":\"CNY\""
          + "},"
          + "\"mchid\":\"1230000109\","
          + "\"description\":\"Image形象店-深圳騰大-QQ公仔\(zhòng)","
          + "\"notify_url\":\"https://www.weixin.qq.com/wxpay/pay.php\","
          + "\"out_trade_no\":\"1217752501201407033233368018\","
          + "\"goods_tag\":\"WXG\","
          + "\"appid\":\"wxd678efh567hg6787\","
          + "\"attach\":\"自定義數(shù)據(jù)說明\","
          + "\"detail\": {"
          + "\"invoice_id\":\"wx123\","
          + "\"goods_detail\": ["
          + "{"
          + "\"goods_name\":\"iPhoneX 256G\","
          + "\"wechatpay_goods_id\":\"1001\","
          + "\"quantity\":1,"
          + "\"merchant_goods_id\":\"商品編碼\","
          + "\"unit_price\":828800"
          + "},"
          + "{"
          + "\"goods_name\":\"iPhoneX 256G\","
          + "\"wechatpay_goods_id\":\"1001\","
          + "\"quantity\":1,"
          + "\"merchant_goods_id\":\"商品編碼\","
          + "\"unit_price\":828800"
          + "}"
          + "],"
          + "\"cost_price\":608800"
          + "},"
          + "\"scene_info\": {"
          + "\"store_info\": {"
          + "\"address\":\"廣東省深圳市南山區(qū)科技中一道10000號(hào)\","
          + "\"area_code\":\"440305\","
          + "\"name\":\"騰訊大廈分店\","
          + "\"id\":\"0001\""
          + "},"
          + "\"device_id\":\"013467007045764\","
          + "\"payer_client_ip\":\"14.23.150.211\""
          + "}"
          + "}";
  StringEntity entity = new StringEntity(reqdata,"utf-8");
  entity.setContentType("application/json");
  httpPost.setEntity(entity);
  httpPost.setHeader("Accept", "application/json");

  //完成簽名并執(zhí)行請求
  CloseableHttpResponse response = httpClient.execute(httpPost);

  try {
      int statusCode = response.getStatusLine().getStatusCode();
      if (statusCode == 200) { //處理成功
          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
      } else if (statusCode == 204) { //處理成功,無返回Body
          System.out.println("success");
      } else {
          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
          throw new IOException("request failed");
      }
  } finally {
      response.close();
  }
}
try {
  $resp = $client->request(
      'POST',
      'https://api.mch.weixin.qq.com/v3/pay/transactions/app', //請求URL
      [
          // JSON請求體
          'json' => [
              "time_expire" => "2018-06-08T10:34:56+08:00", 
              "amount" => [
                  "total" => 100, 
                  "currency" => "CNY", 
              ],
              "mchid" => "1230000109", 
              "description" => "Image形象店-深圳騰大-QQ公仔", 
              "notify_url" => "https://www.weixin.qq.com/wxpay/pay.php", 
              "out_trade_no" => "1217752501201407033233368018", 
              "goods_tag" => "WXG", 
              "appid" => "wxd678efh567hg6787", 
              "attach" => "自定義數(shù)據(jù)說明", 
              "detail" => [
                  "invoice_id" => "wx123", 
                  "goods_detail" => [
                      [
                          "goods_name" => "iPhoneX 256G", 
                          "wechatpay_goods_id" => "1001", 
                          "quantity" => 1, 
                          "merchant_goods_id" => "商品編碼", 
                          "unit_price" => 828800, 
                      ],
                      [
                          "goods_name" => "iPhoneX 256G", 
                          "wechatpay_goods_id" => "1001", 
                          "quantity" => 1, 
                          "merchant_goods_id" => "商品編碼", 
                          "unit_price" => 828800, 
                      ],
                  ],
                  "cost_price" => 608800, 
              ],
              "scene_info" => [
                  "store_info" => [
                      "address" => "廣東省深圳市南山區(qū)科技中一道10000號(hào)", 
                      "area_code" => "440305", 
                      "name" => "騰訊大廈分店", 
                      "id" => "0001", 
                  ],
                  "device_id" => "013467007045764", 
                  "payer_client_ip" => "14.23.150.211", 
              ]
          ],
          'headers' => [ 'Accept' => 'application/json' ]
      ]
  );
  $statusCode = $resp->getStatusCode();
  if ($statusCode == 200) { //處理成功
      echo "success,return body = " . $resp->getBody()->getContents()."\n";
  } else if ($statusCode == 204) { //處理成功,無返回Body
      echo "success";
  }
} catch (RequestException $e) {
  // 進(jìn)行錯(cuò)誤處理
  echo $e->getMessage()."\n";
  if ($e->hasResponse()) {
      echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
  }
  return;

}

func CreateOrder() {
       // 初始化客戶端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
    //設(shè)置請求地址
  URL := "https://api.mch.weixin.qq.com/v3/pay/transactions/app"
  //設(shè)置請求信息,此處也可以使用結(jié)構(gòu)體來進(jìn)行請求
  mapInfo := map[string]interface{}{
    "mchid": "1900006XXX",
    "out_trade_no": "APP1217752501201407033233368018",
    "appid": "wxb4ba3c02aa476XXX",
    "description": "Image形象店-深圳騰大-QQ公仔",
    "notify_url": "https://weixin.qq.com/",
    "amount": map[string]interface{}{
      "total": 1,
      "currency": "CNY",
    },
  }

  // 發(fā)起請求
  response, err := client.Post(ctx, URL, mapInfo)
  if err != nil{
    log.Printf("client post err:%s",err)
    return
  }
  // 校驗(yàn)回包內(nèi)容是否有邏輯錯(cuò)誤
  err = core.CheckResponse(response)
  if err != nil{
    log.Printf("check response err:%s",err)
    return
  }
  // 讀取回包信息
  body, err := ioutil.ReadAll(response.Body)
  if err != nil{
    log.Printf("read response body err:%s",err)
    return
  }
  fmt.Println(string(body))
}
    

重要參數(shù)說明

? out_trade_no:商戶系統(tǒng)內(nèi)部訂單號(hào),只能是數(shù)字、大小寫字母_-*且在同一個(gè)商戶號(hào)下唯一

? description:商品描述

? notify_url:支付回調(diào)通知URL,該地址必須為直接可訪問的URL,不允許攜帶查詢串

? total:訂單總金額,單位為分

更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請參見APP下單API接口文檔

步驟說明:通過APP下單API成功獲取預(yù)支付交易會(huì)話標(biāo)識(shí)(prepay_id)后,需要通過OpenSDK來調(diào)起微信支付收銀臺(tái)

  • 該步驟請使用開放平臺(tái)的官方OpenSDK:
    IOS OpenSDK下載地址
    Android OpenSDK下載地址
  • SDK的調(diào)用需要攜帶簽名(參與簽名的參數(shù)為:appid、partnerid、prepayid、package、noncestr、timestamp,參數(shù)區(qū)分大小寫)
  • 重要入?yún)⒄f明:
    • package:取固定值Sign=WXPay
    • signType:該接口V3版本僅支持RSA
    • paySign:簽名

    paySign生成規(guī)則、響應(yīng)詳情及錯(cuò)誤碼請參見APP調(diào)起支付接口文檔

iOS SDK調(diào)用說明

  • 一、拉起支付

    商戶服務(wù)器生成支付訂單,先調(diào)用APP下單API生成預(yù)付單,獲取到prepay_id后將參數(shù)再次簽名傳輸給APP發(fā)起支付。以下是調(diào)起微信支付的關(guān)鍵代碼:

    PayReq *request = [[[PayReq alloc] init] autorelease];
    
    request.partnerId = @"10000100";
    
    request.prepayId= @"1101000000140415649af9fc314aa427";
    
    request.package = @"Sign=WXPay";
    
    request.nonceStr= @"a462b76e7436e98e0ed6e13c64b4fd1c";
    
    request.timeStamp= @"1397527777";
    
    request.sign= @"582282D72DD2B03AD892830965F428CB16E7A256";
    
    [WXApi sendReq:request]
                                

    注意:該sign生成字段名列表見調(diào)起支付API

  • 二、SDK結(jié)果回調(diào)

    按照微信SDK Sample,在類實(shí)現(xiàn)onResp函數(shù),支付完成后,微信APP會(huì)返回到商戶APP并回調(diào)onResp函數(shù),開發(fā)者需要在該函數(shù)中接收通知,判斷返回錯(cuò)誤碼, 如果支付成功則去后臺(tái)查詢支付結(jié)果再展示用戶實(shí)際支付結(jié)果。注意 一定不能以客戶端返回作為用戶支付的結(jié)果,應(yīng)以服務(wù)器端接收的支付通知或查詢API返回的結(jié)果為準(zhǔn)。代碼示例如下:

    -(void)onResp:(BaseResp*)resp{
    
    if ([respisKindOfClass:[PayRespclass]]){
    
        PayResp*response=(PayResp*)resp;
    
        switch(response.errCode){
    
                    caseWXSuccess: //服務(wù)器端查詢支付通知或查詢API返回的結(jié)果再提示成功
    
                              NSlog(@"支付成功");
    
                    break;
    
                    default:
    
                              NSlog(@"支付失敗,retcode=%d",resp.errCode);
    
                    break;
    
          }
    
      }
    
    }

    回調(diào)中errCode值列表:

    名稱 描述 解決方案
    -2 用戶取消 無需處理。發(fā)生場景:用戶不支付了,點(diǎn)擊取消,返回APP。
    0 成功 展示成功頁面
    -1 錯(cuò)誤 可能的原因:簽名錯(cuò)誤、未注冊APPID、項(xiàng)目設(shè)置APPID不正確、注冊的APPID與設(shè)置的不匹配、其他異常等。

Android SDK調(diào)用說明

  • 一、SDK拉起支付

    商戶服務(wù)器生成支付訂單,先調(diào)用APP下單API生成預(yù)付單,獲取到prepay_id后將參數(shù)再次簽名傳輸給APP發(fā)起支付。以下是調(diào)起微信支付的關(guān)鍵代碼:

    IWXAPI api;
    
      PayReq request = new PayReq();
      
      request.appId = "wxd930ea5d5a258f4f";
      
      request.partnerId = "1900000109";
      
      request.prepayId= "1101000000140415649af9fc314aa427",;
      
      request.packageValue = "Sign=WXPay";
      
      request.nonceStr= "1101000000140429eb40476f8896f4c9";
      
      request.timeStamp= "1398746574";
      
      request.sign= "7FFECB600D7157C5AA49810D2D8F28BC2811827B";
      
      api.sendReq(request);

    注意:該sign生成字段名列表見調(diào)起支付API

  • 二、支付結(jié)果回調(diào)

    參照微信SDK Sample,在net.sourceforge.simcpux.wxapi包路徑中實(shí)現(xiàn)WXPayEntryActivity類(包名或類名不一致會(huì)造成無法回調(diào)),在WXPayEntryActivity類中實(shí)現(xiàn)onResp函數(shù),支付完成后,微信APP會(huì)返回到商戶APP并回調(diào)onResp函數(shù),開發(fā)者需要在該函數(shù)中接收通知,判斷返回錯(cuò)誤碼, 如果支付成功則去后臺(tái)查詢支付結(jié)果再展示用戶實(shí)際支付結(jié)果。注意一定不能以客戶端返回作為用戶支付的結(jié)果,應(yīng)以服務(wù)器端的接收的支付通知或查詢API返回的結(jié)果為準(zhǔn)。代碼示例如下:

    publicvoidonResp(BaseRespresp){
    
        if(resp.getType()==ConstantsAPI.COMMAND_PAY_BY_WX){
    
        Log.d(TAG,"onPayFinish,errCode="+resp.errCode);
    
        AlertDialog.Builderbuilder=newAlertDialog.Builder(this);
    
        builder.setTitle(R.string.app_tip);
    
        }
    
    }

    回調(diào)中errCode值列表:

    名稱 描述 解決方案
    0 成功 展示成功頁面
    -1 錯(cuò)誤 可能的原因:簽名錯(cuò)誤、未注冊APPID、項(xiàng)目設(shè)置APPID不正確、注冊的APPID與設(shè)置的不匹配、其他異常等。
    -2 用戶取消 無需處理。發(fā)生場景:用戶不支付了,點(diǎn)擊取消,返回APP。
3.2.3.【服務(wù)端】接收支付結(jié)果通知

步驟說明:當(dāng)用戶完成支付,微信會(huì)把相關(guān)支付結(jié)果將通過異步回調(diào)的方式通知商戶,商戶需要接收處理,并按文檔規(guī)范返回應(yīng)答

注意

  • 支付結(jié)果通知是以POST 方法訪問商戶設(shè)置的通知url,通知的數(shù)據(jù)以JSON 格式通過請求主體(BODY)傳輸。通知的數(shù)據(jù)包括了加密的支付結(jié)果詳情
  • 加密不能保證通知請求來自微信。微信會(huì)對(duì)發(fā)送給商戶的通知進(jìn)行簽名,并將簽名值放在通知的HTTP頭Wechatpay-Signature。商戶應(yīng)當(dāng)驗(yàn)證簽名,以確認(rèn)請求來自微信,而不是其他的第三方。簽名驗(yàn)證的算法請參考 《微信支付API v3簽名驗(yàn)證》
  • 支付通知http應(yīng)答碼為200或204才會(huì)當(dāng)作正常接收,當(dāng)回調(diào)處理異常時(shí),應(yīng)答的HTTP狀態(tài)碼應(yīng)為500,或者4xx
  • 商戶成功接收到回調(diào)通知后應(yīng)返回成功的http應(yīng)答碼為200或204
  • 同樣的通知可能會(huì)多次發(fā)送給商戶系統(tǒng)。商戶系統(tǒng)必須能夠正確處理重復(fù)的通知。 推薦的做法是,當(dāng)商戶系統(tǒng)收到通知進(jìn)行處理時(shí),先檢查對(duì)應(yīng)業(yè)務(wù)數(shù)據(jù)的狀態(tài),并判斷該通知是否已經(jīng)處理。如果未處理,則再進(jìn)行處理;如果已處理,則直接返回結(jié)果成功。在對(duì)業(yè)務(wù)數(shù)據(jù)進(jìn)行狀態(tài)檢查和處理之前,要采用數(shù)據(jù)鎖進(jìn)行并發(fā)控制,以避免函數(shù)重入造成的數(shù)據(jù)混亂
  • 對(duì)后臺(tái)通知交互時(shí),如果微信收到商戶的應(yīng)答不符合規(guī)范或超時(shí),微信認(rèn)為通知失敗,微信會(huì)通過一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。(通知頻率為15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 總計(jì) 24h4m)

更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請參見 JSAPI / APP / H5 / Native / 小程序支付通知API接口文檔

3.2.4. 【服務(wù)端】查詢訂單

步驟說明:當(dāng)商戶后臺(tái)、網(wǎng)絡(luò)、服務(wù)器等出現(xiàn)異常,商戶系統(tǒng)最終未接收到支付通知時(shí),商戶可通過查詢訂單接口核實(shí)訂單支付狀態(tài)

示例代碼(通過微信訂單號(hào)查詢):


public void QueryOrder() throws Exception {
   
  //請求URL
  URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/pay/transactions/id/4200000745202011093730578574");
  uriBuilder.setParameter("mchid", mchId);
 
  //完成簽名并執(zhí)行請求
  HttpGet httpGet = new HttpGet(uriBuilder.build());
  httpGet.addHeader("Accept", "application/json");
  CloseableHttpResponse response = httpClient.execute(httpGet);
   
  try {
      int statusCode = response.getStatusLine().getStatusCode();
      if (statusCode == 200) {
          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
      } else if (statusCode == 204) {
          System.out.println("success");
      } else {
          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
          throw new IOException("request failed");
      }
  } finally {
      response.close();
  }
}
      

try {
    $resp = $client->request(
        'GET',
        'https://api.mch.weixin.qq.com/v3/pay/transactions/id/1217752501201407033233368018?mchid=1230000109', //請求URL
        [
            'headers' => [ 'Accept' => 'application/json']
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //處理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //處理成功,無返回Body
        echo "success";
    }
} catch (RequestException $e) {
    // 進(jìn)行錯(cuò)誤處理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
}

func QueryOrder() {
       // 初始化客戶端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
    //設(shè)置請求地址
    URL := "https://api.mch.weixin.qq.com/v3/pay/transactions/id/1217752501201407033233368018?mchid=1900000000"
    // 發(fā)起請求
    response, err := client.Get(ctx, URL)
    if err != nil{
        log.Printf("client get err:%s",err)
        return
    }
    // 校驗(yàn)回包內(nèi)容是否有邏輯錯(cuò)誤
    err = core.CheckResponse(response)
    if err != nil{
        log.Printf("check response err:%s",err)
        return
    }
    // 讀取回包信息
    body, err := ioutil.ReadAll(response.Body)
    if err != nil{
        log.Printf("read response body err:%s",err)
        return
    }
    fmt.Println(string(body))
}
    

注意:

  • 查詢訂單可通過微信支付訂單號(hào)商戶訂單號(hào)兩種方式查詢,兩種查詢方式返回結(jié)果相同

更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請參見 JSAPI / APP / H5 / Native / 小程序查詢訂單API接口文檔

3.2.5. 【服務(wù)端】關(guān)閉訂單

步驟說明:當(dāng)商戶訂單支付失敗需要生成新單號(hào)重新發(fā)起支付,要對(duì)原訂單號(hào)調(diào)用關(guān)單,避免重復(fù)支付;系統(tǒng)下單后,用戶支付超時(shí),系統(tǒng)退出不再受理,避免用戶繼續(xù),請調(diào)用關(guān)單接口

示例代碼


  public void CloseOrder() throws Exception {
     
    //請求URL
    HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/sdkphp12345678920201028112429/close");
    //請求body參數(shù)
    String reqdata ="{\"mchid\": \""+mchId+"\"}";
     
    StringEntity entity = new StringEntity(reqdata,"utf-8");
    entity.setContentType("application/json");
    httpPost.setEntity(entity);
    httpPost.setHeader("Accept", "application/json");
   
  //完成簽名并執(zhí)行請求
    CloseableHttpResponse response = httpClient.execute(httpPost);
    try {
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) {
            System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
        } else if (statusCode == 204) {
            System.out.println("success");
        } else {
            System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
            throw new IOException("request failed");
        }
    } finally {
        response.close();
    }
  }
  
try {
    $resp = $client->request(
        'POST',
        'https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}/close', //請求URL
        [
            // JSON請求體
            'json' => [
                "mchid " => "1230000109",
            ],
            'headers' => [ 'Accept' => 'application/json' ]
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //處理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //處理成功,無返回Body
        echo "success";
    }
  } catch (RequestException $e) {
    // 進(jìn)行錯(cuò)誤處理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
  }
  

func CloseOrder() {
       // 初始化客戶端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
    //設(shè)置請求地址
    URL := "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/1217752501201407033233368018/close"
    //設(shè)置請求信息,此處也可以使用結(jié)構(gòu)體來進(jìn)行請求
    mapInfo := map[string]interface{}{
      "mchid": "1900006891",
    }
  
    // 發(fā)起請求
    response, err := client.Post(ctx, URL, mapInfo)
    if err != nil{
      log.Printf("client post err:%s",err)
      return
    }
    // 校驗(yàn)回包內(nèi)容是否有邏輯錯(cuò)誤
    err = core.CheckResponse(response)
    if err != nil{
      log.Printf("check response err:%s",err)
      return
    }
    // 讀取回包信息
    body, err := ioutil.ReadAll(response.Body)
    if err != nil{
      log.Printf("read response body err:%s",err)
      return
    }
    fmt.Println(string(body))
}
    

注意

  • 訂單生成后不能馬上調(diào)用關(guān)單接口,最短調(diào)用時(shí)間間隔為5分鐘
  • 已支付成功的訂單不能關(guān)閉

更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請參見 JSAPI / APP / H5 / Native / 小程序接口文檔

3.2.6. 【服務(wù)端】申請交易賬單

步驟說明:微信支付按天提供交易賬單文件,商戶可以通過該接口獲取賬單文件的下載地址

示例代碼


public void TradeBill() throws Exception {
   
  //請求URL
  URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/bill/tradebill");
  uriBuilder.setParameter("bill_date", "2020-11-09");
  uriBuilder.setParameter("bill_type", "ALL");
 
  //完成簽名并執(zhí)行請求
  HttpGet httpGet = new HttpGet(uriBuilder.build());
  httpGet.addHeader("Accept", "application/json");
  CloseableHttpResponse response = httpClient.execute(httpGet);
 
  try {
      int statusCode = response.getStatusLine().getStatusCode();
      if (statusCode == 200) {
          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
      } else if (statusCode == 204) {
          System.out.println("success");
      } else {
          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
          throw new IOException("request failed");
      }
  } finally {
      response.close();
  }
}
try {
    $resp = $client->request(
        'GET',
        'https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=2019-06-11&bill_type=ALL', //請求URL
        [
            'headers' => [ 'Accept' => 'application/json']
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //處理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //處理成功,無返回Body
        echo "success";
    }
} catch (RequestException $e) {
    // 進(jìn)行錯(cuò)誤處理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
}
      

func TradeBill() {
       // 初始化客戶端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
   //設(shè)置請求地址
    URL := "https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=2019-06-11&bill_type=ALL"
  // 發(fā)起請求
  response, err := client.Get(ctx, URL)
  if err != nil{
    log.Printf("client get err:%s",err)
    return
  }
  // 校驗(yàn)回包內(nèi)容是否有邏輯錯(cuò)誤
  err = core.CheckResponse(response)
  if err != nil{
    log.Printf("check response err:%s",err)
    return
  }
  // 讀取回包信息
  body, err := ioutil.ReadAll(response.Body)
  if err != nil{
    log.Printf("read response body err:%s",err)
    return
  }
  fmt.Println(string(body))
}
    

注意

更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請參見 JSAPI / APP / H5 / Native / 小程序接口文檔

3.2.7. 【服務(wù)端】下載賬單

步驟說明:通過申請交易賬單接口獲取到賬單下載地址(download_url)后,再通過該接口獲取到對(duì)應(yīng)的賬單文件,文件內(nèi)包含交易相關(guān)的金額、時(shí)間、營銷等信息,供商戶核對(duì)訂單、退款、銀行到賬等情況

示例代碼


public void DownloadUrl(String download_url) throws Exception{
  PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
   
  //初始化httpClient
  //該接口無需進(jìn)行簽名驗(yàn)證、通過withValidator((response) -> true)實(shí)現(xiàn)
  httpClient =  WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, merchantPrivateKey).withValidator((response) -> true).build();
   
  //請求URL
  //賬單文件的下載地址的有效時(shí)間為30s
  URIBuilder uriBuilder = new URIBuilder(download_url);
  HttpGet httpGet = new HttpGet(uriBuilder.build());
  httpGet.addHeader("Accept", "application/json");
   
  //執(zhí)行請求
  CloseableHttpResponse response = httpClient.execute(httpGet);
  try {
      int statusCode = response.getStatusLine().getStatusCode();
      if (statusCode == 200) {
          System.out.println("success,return body = " + EntityUtils.toString(response.getEntity()));
      } else if (statusCode == 204) {
          System.out.println("success");
      } else {
          System.out.println("failed,resp code = " + statusCode+ ",return body = " + EntityUtils.toString(response.getEntity()));
          throw new IOException("request failed");
      }
  } finally {
      response.close();
  }
}
try {
    $resp = $client->request(
        'GET',
        'https://api.mch.weixin.qq.com/v3/billdownload/file?token=xx', //請求URL
        [
            'headers' => [ 'Accept' => 'application/json']
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //處理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //處理成功,無返回Body
        echo "success";
    }
} catch (RequestException $e) {
    // 進(jìn)行錯(cuò)誤處理
    echo $e->getMessage()."\n";
    if ($e->hasResponse()) {
        echo "failed,resp code = " . $e->getResponse()->getStatusCode() . " return body = " . $e->getResponse()->getBody() . "\n";
    }
    return;
}

func DownloadUrl() {
       // 初始化客戶端
    ctx := context.TODO()
    opts, err := SetUp()
    if err != nil {
        return
    }
    client, err := core.NewClient(ctx, opts...,)
    if err != nil{
        log.Printf("init client err:%s",err)
        return
    }
    //設(shè)置請求地址
    URL := "https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx"  //申請賬單接口獲取到的download_url
  // 發(fā)起請求
  response, err := client.Get(ctx, URL)
  if err != nil{
    log.Printf("client get err:%s",err)
    return
  }
  // 校驗(yàn)回包內(nèi)容是否有邏輯錯(cuò)誤
  err = core.CheckResponse(response)
  if err != nil{
    log.Printf("check response err:%s",err)
    return
  }
  // 讀取回包信息
  body, err := ioutil.ReadAll(response.Body)
  if err != nil{
    log.Printf("read response body err:%s",err)
    return
  }
  fmt.Println(string(body))
}
    

注意

? 賬單文件的下載地址的有效時(shí)間為30s

? 強(qiáng)烈建議商戶將實(shí)際賬單文件的哈希值和之前從接口獲取到的哈希值進(jìn)行比對(duì),以確認(rèn)數(shù)據(jù)的完整性

更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請參見 JSAPI / APP / H5 / Native / 小程序下載賬單API接口文檔

4. 常見問題

Q:微信APP支付,前端調(diào)起的時(shí)候返回errcode = -1該如何排查?

A:1. 查看APP下單參數(shù)返回是否正常,是否有正確的在調(diào)用SDK前獲取了正確的prepay_id;

  •  2.查看調(diào)用SDK簽名是否正確,請注意以下幾點(diǎn):
  • a) 參與簽名的參數(shù)名大小寫一定要與文檔中保持一致;

    b) APP下單返回的簽名和調(diào)用SDK使用的簽名不是同一個(gè),調(diào)用SDK需要單獨(dú)根據(jù)SDK參數(shù)生成簽名;

  • 3. 檢查客戶端調(diào)用sendReq(PayReq)對(duì)象賦值的正確性(必要時(shí)讓商戶提供數(shù)據(jù)),若通過異步獲取到后臺(tái)數(shù)據(jù),比如data對(duì)象是通過異步請求得到的對(duì)象:request.appId = data.appid; 實(shí)際appid屬性值為空;
  • 4. 檢查對(duì)應(yīng)的開發(fā)配置,包括iOS的appid配置,Android的包名及包簽名設(shè)置。
Q:app調(diào)用“喚起支付api”返回:商戶支付下單id非法

A:請確認(rèn)喚起支付參數(shù)字段名是否與文檔的一致。

Q:服務(wù)商模式下,調(diào)用APP下單接口,返回“特殊子商戶未授權(quán)的產(chǎn)品權(quán)限”

A:APP支付需要進(jìn)行單獨(dú)的授權(quán)開通才可使用,請前往服務(wù)商平臺(tái)子商戶管理中找到對(duì)應(yīng)的子商戶授權(quán)服務(wù)商APP支付權(quán)限。

Q:調(diào)用APP下單接口,返回“sub_appid與sub_mch_id不匹配”

A:在調(diào)用APP下單接口前,需保證子商戶號(hào)與子商戶APP的appid存在綁定關(guān)系,請服務(wù)商前往服務(wù)商平臺(tái)的子商戶管理頁面中操作綁定。



技術(shù)咨詢

文檔反饋