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

商戶進(jìn)件
特約商戶進(jìn)件
基礎(chǔ)支付
JSAPI支付
APP支付
H5支付
Native支付
小程序支付
合單支付
付款碼支付
經(jīng)營(yíng)能力
支付即服務(wù)
點(diǎn)金計(jì)劃
行業(yè)方案
平臺(tái)收付通
智慧商圈
微信支付分停車服務(wù)
電子發(fā)票
營(yíng)銷工具
代金券
商家券
委托營(yíng)銷
支付有禮
小程序發(fā)券插件
H5發(fā)券
圖片上傳(營(yíng)銷專用)
現(xiàn)金紅包
資金應(yīng)用
分賬
連鎖品牌分賬
風(fēng)險(xiǎn)合規(guī)
商戶開(kāi)戶意愿確認(rèn)
消費(fèi)者投訴2.0
商戶平臺(tái)處置通知
其他能力
圖片上傳
視頻上傳
微信支付平臺(tái)證書(shū)

JSAPI支付開(kāi)發(fā)指引

1. 接口規(guī)則

為了在保證支付安全的前提下,帶給商戶簡(jiǎn)單、一致且易用的開(kāi)發(fā)體驗(yàn),我們推出了全新的微信支付APIv3接口。該版本API的具體規(guī)則請(qǐng)參考“APIv3接口規(guī)則

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

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

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

測(cè)試步驟

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

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

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

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

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

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

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


@Before
public void setup() throws IOException {
    // 加載商戶私鑰(privateKey:私鑰字符串)
    PrivateKey merchantPrivateKey = PemUtil
            .loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
 
    // 加載平臺(tái)證書(shū)(mchId:商戶號(hào),mchSerialNo:商戶證書(shū)序列號(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證書(shū)序列號(hào)
$merchantPrivateKey = PemUtil::loadPrivateKey('./path/to/mch/private/key.pem'); // 商戶私鑰文件路徑
 
// 微信支付平臺(tái)配置
$wechatpayCertificate = PemUtil::loadCertificate('./path/to/wechatpay/cert.pem'); // 微信支付平臺(tái)證書(shū)文件路徑
 
// 構(gòu)造一個(gè)WechatPayMiddleware
$wechatpayMiddleware = WechatPayMiddleware::builder()
    ->withMerchant($merchantId, $merchantSerialNumber, $merchantPrivateKey) // 傳入商戶相關(guān)配置
    ->withWechatPay([ $wechatpayCertificate ]) // 可傳入多個(gè)微信支付平臺(tái)證書(shū),參數(shù)類型為array
    ->build();
 
// 將WechatPayMiddleware添加到Guzzle的HandlerStack中
$stack = GuzzleHttp\HandlerStack::create();
$stack->push($wechatpayMiddleware, 'wechatpay');
 
// 創(chuàng)建Guzzle HTTP Client時(shí),將HandlerStack傳入,接下來(lái),正常使用Guzzle發(fā)起API請(qǐng)求,WechatPayMiddleware會(huì)自動(dòng)地處理簽名和驗(yàn)簽
$client = new GuzzleHttp\Client(['handler' => $stack]);

/*
    Package core 微信支付api v3 go http-client 基礎(chǔ)庫(kù),你可以使用它來(lái)創(chuàng)建一個(gè)client,并向微信支付發(fā)送http請(qǐng)求
    只需要你在初始化客戶端的時(shí)候,傳遞credential以及validator
    credential用來(lái)生成http header中的authorization信息
    validator則用來(lái)校驗(yàn)回包是否被篡改
    如果http請(qǐng)求返回的err為nil,一般response.Body 都不為空,你可以嘗試對(duì)其進(jìn)行序列化
    請(qǐng)注意及時(shí)關(guān)閉response.Body
    注意:使用微信支付apiv3 go庫(kù)需要引入相關(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 := ""
    //商戶證書(shū)序列號(hào)
    mchCertSerialNumber := ""
    //商戶私鑰文件路徑
    privateKeyPath := ""
    //平臺(tái)證書(shū)文件路徑
    wechatCertificatePath := ""

    // 加載商戶私鑰
    privateKey, err := utils.LoadPrivateKeyWithPath(privateKeyPath)
    if err != nil {
        log.Printf("load private err:%s", err.Error())
        return nil, err
    }
    // 加載微信支付平臺(tái)證書(shū)
    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)證書(shū),用于校驗(yàn)回包信息用
    }
    return opts, nil
}

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

說(shuō)明:

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

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

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

    1.簽名生成

    2.簽名驗(yàn)證

    3.敏感信息加解密

    4.merchantPrivateKey(私鑰)

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

    6.APIV3Key(V3 key)

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

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

2.2.1. 設(shè)置支付目錄

? 支付授權(quán)目錄說(shuō)明

a、商戶最后請(qǐng)求拉起微信支付收銀臺(tái)的頁(yè)面地址我們稱之為“支付目錄”,例如:https://www.weixin.com/pay.php。

b、商戶實(shí)際的支付目錄必須和在微信支付商戶平臺(tái)設(shè)置的一致,否則會(huì)報(bào)錯(cuò)“當(dāng)前頁(yè)面的URL未注冊(cè):”

? 支付授權(quán)目錄設(shè)置說(shuō)明

登錄【微信支付商戶平臺(tái)-->產(chǎn)品中心-->開(kāi)發(fā)配置】,設(shè)置后一般5分鐘內(nèi)生效。


圖1支付目錄配置

? 支付授權(quán)目錄校驗(yàn)規(guī)則說(shuō)明

a、如果支付授權(quán)目錄設(shè)置為頂級(jí)域名(例如:https://www.weixin.com/ ),那么只校驗(yàn)頂級(jí)域名,不校驗(yàn)后綴;

b、如果支付授權(quán)目錄設(shè)置為多級(jí)目錄,就會(huì)進(jìn)行全匹配,例如設(shè)置支付授權(quán)目錄為https://www.weixin.com/abc/123/,則實(shí)際請(qǐng)求頁(yè)面目錄不能為https://www.weixin.com/abc/,也不能為https://www.weixin.com/abc/123/pay/,必須為https://www.weixin.com/abc/123/


圖1 支付目錄配置


2.2.2. 設(shè)置授權(quán)域名

? 授權(quán)域名說(shuō)明:開(kāi)發(fā)JSAPI支付時(shí),在JSAPI下單接口中要求必傳用戶openid,而獲取openid則需要您在公眾平臺(tái)設(shè)置獲取openid的域名,只有被設(shè)置過(guò)的域名才是一個(gè)有效的獲取openid的域名,否則將獲取失敗。具體配置頁(yè)如圖2所示

? 授權(quán)域名設(shè)置說(shuō)明:登錄【微信公眾平臺(tái)-->公眾號(hào)設(shè)置-->功能設(shè)置】


圖2 微信網(wǎng)頁(yè)授權(quán)域名設(shè)置

3. 快速接入

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

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

步驟3 用戶下單發(fā)起支付,商戶可通過(guò)JSAPI下單創(chuàng)建支付訂單。

步驟8 商戶可在微信瀏覽器內(nèi)通過(guò)JSAPI調(diào)起支付API調(diào)起微信支付,發(fā)起支付請(qǐng)求。

步驟15 用戶支付成功后,商戶可接收到微信支付支付結(jié)果通知支付結(jié)果通知API

步驟20 商戶在沒(méi)有接收到微信支付結(jié)果通知的情況下需要主動(dòng)調(diào)用查詢訂單API查詢支付結(jié)果。

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

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

注意

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

步驟說(shuō)明:用戶通過(guò)商戶下發(fā)的模板消息或掃描二維碼在微信內(nèi)進(jìn)入商戶網(wǎng)頁(yè),當(dāng)用戶選擇相關(guān)商戶購(gòu)買時(shí),商戶系統(tǒng)先調(diào)用該接口在微信支付服務(wù)后臺(tái)生成預(yù)支付交易單。

示例代碼


public void CreateOrder() throws Exception{

  //請(qǐng)求URL
  HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi");
  // 請(qǐng)求body參數(shù)
  String reqdata = "{"
          + "\"sp_appid\":\"wx8888888888888888\","
          + "\"sp_mchid\":\"1230000109\","
          + "\"sub_mchid\":\"1900000109\","
          + "\"sub_appid\":\"wxd678efh567hg6999\","
          + "\"description\":\"Image形象店-深圳騰大-QQ公仔\(zhòng)","
          + "\"out_trade_no\":\"1217752501201407033233368018\","
          + "\"time_expire\":\"2018-06-08T10:34:56+08:00\","
          + "\"attach\":\"自定義數(shù)據(jù)說(shuō)明\","
          + "\"notify_url\":\"https://www.weixin.qq.com/wxpay/pay.php\","
          + "\"goods_tag\":\"WXG\","
          + "\"settle_info\": {"
          + "\"profit_sharing\":false,"
          + "},"
          + "\"amount\": {"
          + "\"total\":100,"
          + "\"currency\":\"CNY\""
          + "},"
          + "\"payer\": {"
          + "\"sp_openid\":\"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o\","
          + "\"sub_openid\":\"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o\""
          + "},"
          + "\"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í)行請(qǐng)求
  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) { //處理成功,無(wú)返回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/partner/transactions/jsapi', //請(qǐng)求URL
        [
            // JSON請(qǐng)求體
            'json' => [
                "sp_appid" => "wx8888888888888888", 
                "sp_mchid" => "1230000109", 
                "sub_mchid" => "1900000109", 
                "sub_appid" => "wxd678efh567hg6999", 
                "description" => "Image形象店-深圳騰大-QQ公仔", 
                "out_trade_no" => "1217752501201407033233368018", 
                "time_expire" => "2018-06-08T10:34:56+08:00", 
                "attach" => "自定義數(shù)據(jù)說(shuō)明", 
                "notify_url" => "https://www.weixin.qq.com/wxpay/pay.php", 
                "goods_tag" => "WXG", 
                "settle_info" => [
                    "profit_sharing" => false, 
                ],
                "amount" => [
                    "total" => 100, 
                    "currency" => "CNY", 
                ],
                "payer" => [
                    "sp_openid" => "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o", 
                    "sub_openid" => "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o", 
                ],
                "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) { //處理成功,無(wú)返回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è)置請(qǐng)求地址
  URL := "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi"
  //設(shè)置請(qǐng)求信息,此處也可以使用結(jié)構(gòu)體來(lái)進(jìn)行請(qǐng)求
  mapInfo := map[string]interface{}{
    "sp_mchid": "1900007XXX",
    "sub_mchid": "1900008XXX",
    "out_trade_no": "1217752501201407033233368318",
    "sp_appid": "wxdace645e0bc2cXXX",
    "sub_appid": "wxdace645e0bc2cXXX",
    "description": "Image形象店-深圳騰大-QQ公仔",
    "notify_url": "https://weixin.qq.com/",
    "amount": map[string]interface{}{
      "total": 1,
      "currency": "CNY",
    },
    "payer": map[string]interface{}{
      "sp_openid": "o4GgauInH_RCEdvrrNGrntXDuXXX",
    },
  }

  // 發(fā)起請(qǐng)求
  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))
}
    

重要入?yún)⒄f(shuō)明

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

? description:商品描述

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

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

? openid:openid是微信用戶在appid下的唯一用戶標(biāo)識(shí)(appid不同,則獲取到的openid就不同),可用于永久標(biāo)記一個(gè)用戶。openid獲取方式請(qǐng)參考以下文檔小程序獲取openid公眾號(hào)獲取openidAPP獲取openid

更多參數(shù)、響應(yīng)詳情及錯(cuò)誤碼請(qǐng)參見(jiàn)JSAPI下單接口文檔

3.2.2.【客戶端】JSAPI調(diào)起支付

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

注意

? WeixinJSBridge內(nèi)置對(duì)象在其他瀏覽器中無(wú)效

? 此API需要將請(qǐng)求參數(shù)進(jìn)行簽名(參與簽名的參數(shù)為:appId、timeStamp、nonceStr、package,參數(shù)區(qū)分大小寫(xiě))

示例代碼


  function onBridgeReady() {
      WeixinJSBridge.invoke('getBrandWCPayRequest', {
          "appId": "wx2421b1c4370ecxxx",       //公眾號(hào)ID,由商戶傳入    
          "timeStamp": "1395712654",     //時(shí)間戳,自1970年以來(lái)的秒數(shù)    
          "nonceStr": "e61463f8efa94090b1f366cccfbbb444",     //隨機(jī)串    
          "package": "prepay_id=wx21201855730335ac86f8c43d1889123400",
          "signType": "RSA",     //微信簽名方式:    
          "paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7vaRvkYD7rthRAZ\/X+QBhcCYL21N7cHCTUxbQ+EAt6Uy+lwSN22f5YZvI45MLko8Pfso0jm46v5hqcVwrk6uddkGuT+Cdvu4WBqDzaDjnNa5UK3GfE1Wfl2gHxIIY5lLdUgWFts17D4WuolLLkiFZV+JSHMvH7eaLdT9N5GBovBwu5yYKUR7skR8Fu+LozcSqQixnlEZUfyE55feLOQTUYzLmR9pNtPbPsu6WVhbNHMS3Ss2+AehHvz+n64GDmXxbX++IOBvm2olHu3PsOUGRwhudhVf7UcGcunXt8cqNjKNqZLhLw4jq\/xDg==" //微信簽名
      },
      function(res) {
          if (res.err_msg == "get_brand_wcpay_request:ok") {
              // 使用以上方式判斷前端返回,微信團(tuán)隊(duì)鄭重提示:
              //res.err_msg將在用戶支付成功后返回ok,但并不保證它絕對(duì)可靠。
          }
      });
  }
  if (typeof WeixinJSBridge == "undefined") {
      if (document.addEventListener) {
          document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
      } else if (document.attachEvent) {
          document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
          document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
      }
  } else {
      onBridgeReady();
  }	  
  

重要入?yún)⒄f(shuō)明

? package:JSAPI下單接口返回的prepay_id參數(shù)值,提交格式如:prepay_id=***

? signType:簽名類型,該接口V3版本僅支持RSA

? paySign:簽名

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

3.2.3.【服務(wù)端】接收支付結(jié)果通知

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

注意

  • 支付結(jié)果通知是以POST 方法訪問(wèn)商戶設(shè)置的通知url,通知的數(shù)據(jù)以JSON 格式通過(guò)請(qǐng)求主體(BODY)傳輸。通知的數(shù)據(jù)包括了加密的支付結(jié)果詳情
  • 加密不能保證通知請(qǐng)求來(lái)自微信。微信會(huì)對(duì)發(fā)送給商戶的通知進(jìn)行簽名,并將簽名值放在通知的HTTP頭Wechatpay-Signature。商戶應(yīng)當(dāng)驗(yàn)證簽名,以確認(rèn)請(qǐng)求來(lái)自微信,而不是其他的第三方。簽名驗(yàn)證的算法請(qǐng)參考 《微信支付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ì)通過(guò)一定的策略定期重新發(fā)起通知,盡可能提高通知的成功率,但微信不保證通知最終能成功。(通知頻率為15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 總計(jì) 24h4m)

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

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

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

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


public void QueryOrder() throws Exception {
   
  //請(qǐng)求URL
  HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/id/1217752501201407033233368018?sp_mchid=1230000109&sub_mchid=1900000109");
  httpGet.setHeader("Accept", "application/json");

  //完成簽名并執(zhí)行請(qǐng)求
  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) { //處理成功,無(wú)返回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(
        'GET',
        'https://api.mch.weixin.qq.com/v3/pay/partner/transactions/id/1217752501201407033233368018?sp_mchid=1230000109&sub_mchid=1900000109', //請(qǐng)求URL
        [
            'headers' => [ 'Accept' => 'application/json']
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //處理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //處理成功,無(wú)返回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è)置請(qǐng)求地址
  URL := "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/id/4200000985202103031441826014?sp_mchid=1900007XXX&sub_mchid=1900008XXX"
  // 發(fā)起請(qǐng)求
  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))
}
    

注意:

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

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

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

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

示例代碼


  public void CloseOrder() throws Exception {
     
    //請(qǐng)求URL
  HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/{out_trade_no}/close");
  // 請(qǐng)求body參數(shù)
  String reqdata = "{"
          + "\"sp_mchid\":\"1230000109\","
          + "\"sub_mchid\":\"1900000109\""
          + "}";
  StringEntity entity = new StringEntity(reqdata,"utf-8");
  entity.setContentType("application/json");
  httpPost.setEntity(entity);
  httpPost.setHeader("Accept", "application/json");

  //完成簽名并執(zhí)行請(qǐng)求
  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) { //處理成功,無(wú)返回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/partner/transactions/out-trade-no/{out_trade_no}/close', //請(qǐng)求URL
        [
            // JSON請(qǐng)求體
            'json' => [
                "sp_mchid" => "1230000109", 
                "sub_mchid" => "1900000109",
            ],
            'headers' => [ 'Accept' => 'application/json' ]
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //處理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //處理成功,無(wú)返回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è)置請(qǐng)求地址
  URL := "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/1217752501201407033233368018/close"
  //設(shè)置請(qǐng)求信息,此處也可以使用結(jié)構(gòu)體來(lái)進(jìn)行請(qǐng)求
  mapInfo := map[string]interface{}{
    "sp_mchid": "1900007XXX",
    "sub_mchid": "1900008XXX",
  }

  // 發(fā)起請(qǐng)求
  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))
}
    

注意

  • 關(guān)單沒(méi)有時(shí)間限制,建議在訂單生成后間隔幾分鐘(最短5分鐘)再調(diào)用關(guān)單接口,避免出現(xiàn)訂單狀態(tài)同步不及時(shí)導(dǎo)致關(guān)單失敗。
  • 已支付成功的訂單不能關(guān)閉

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

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

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

示例代碼


public void TradeBill() throws Exception {
   
  //請(qǐng)求URL
  HttpGet httpGet = new HttpGet("https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=2019-06-11&sub_mchid=1900000001&bill_type=ALL");
  httpGet.setHeader("Accept", "application/json");

  //完成簽名并執(zhí)行請(qǐng)求
  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) { //處理成功,無(wú)返回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(
        'GET',
        'https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=2019-06-11&sub_mchid=1900000001&bill_type=ALL', //請(qǐng)求URL
        [
            'headers' => [ 'Accept' => 'application/json']
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //處理成功
        echo "success,return body = " . $resp->getBody()->getContents()."\n";
    } else if ($statusCode == 204) { //處理成功,無(wú)返回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è)置請(qǐng)求地址
  URL := "https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=2019-06-11&sub_mchid=1900000001&bill_type=ALL"
  // 發(fā)起請(qǐng)求
  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ò)誤碼請(qǐng)參見(jiàn) JSAPI / APP / H5 / Native / 小程序接口文檔

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

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

示例代碼


public void DownloadUrl(String download_url) throws Exception{
  PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
   
  //初始化httpClient
  //該接口無(wú)需進(jìn)行簽名驗(yàn)證、通過(guò)withValidator((response) -> true)實(shí)現(xiàn)
  httpClient =  WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, merchantPrivateKey).withValidator((response) -> true).build();
   
  //請(qǐng)求URL
  //賬單文件的下載地址的有效時(shí)間為30s
  URIBuilder uriBuilder = new URIBuilder(download_url);
  HttpGet httpGet = new HttpGet(uriBuilder.build());
  httpGet.addHeader("Accept", "application/json");
   
  //執(zhí)行請(qǐng)求
  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', //請(qǐng)求URL
        [
            'headers' => [ 'Accept' => 'application/json']
        ]
    );
    $statusCode = $resp->getStatusCode();
    if ($statusCode == 200) { //處理成功
        echo "success,return body = " . $resp->getReasonPhrase()."\n";
    } else if ($statusCode == 204) { //處理成功,無(wú)返回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è)置請(qǐng)求地址
    URL := "https://api.mch.weixin.qq.com/v3/billdownload/file?token=xxx"  //申請(qǐng)賬單接口獲取到的download_url
  // 發(fā)起請(qǐng)求
  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ò)誤碼請(qǐng)參見(jiàn) JSAPI / APP / H5 / Native / 小程序下載賬單API接口文檔

4. 常見(jiàn)問(wèn)題

Q:獲取OPENID接口報(bào)“此公眾號(hào)并沒(méi)有這些scope的權(quán)限,錯(cuò)誤碼10005”,如下圖所示

A:請(qǐng)按以下步驟進(jìn)行排查:

1. 建議檢查一下公眾號(hào)的功能。比如是不是在訂閱號(hào)/未認(rèn)證的公眾號(hào)里面嘗試調(diào)用認(rèn)證服務(wù)號(hào)的功能

2. 確認(rèn)APPID是否認(rèn)證過(guò)期或者APPID填寫(xiě)錯(cuò)誤

3. 請(qǐng)嘗試使用snsapi_userinfo的授權(quán)登錄方式

Q:JSAPI調(diào)起支付接口報(bào)“商家暫時(shí)沒(méi)有此類交易權(quán)限,請(qǐng)聯(lián)系商家客服”

A:請(qǐng)按以下步驟進(jìn)行排查:

1. 請(qǐng)檢查你的下單接口是否指定了支付用戶的身份,該功能需單獨(dú)開(kāi)通指定身份支付權(quán)限方可使用

2. 請(qǐng)確認(rèn)你使用的商戶號(hào)是否有jsapi支付的權(quán)限,可登錄商戶平臺(tái)-產(chǎn)品中心查看

Q:JSAPI調(diào)起支付接口報(bào)“當(dāng)前頁(yè)面的URL未注冊(cè)”

A:請(qǐng)檢查下單接口中使用的商戶號(hào)是否在商戶平臺(tái)配置了對(duì)應(yīng)的支付目錄,可參考“1.2.1設(shè)置支付目錄”章節(jié)說(shuō)明

Q:獲取OPENID接口報(bào)“redirect_url域名與后臺(tái)配置不一致,錯(cuò)誤碼:10003”

A:請(qǐng)按以下步驟進(jìn)行排查:

1. 檢查下單接口傳的appid與獲取openid接口的appid是否同一個(gè)(需一致)

2. 檢查appid對(duì)應(yīng)的公眾號(hào)后臺(tái),是否配置的授權(quán)域名和獲取openid的域名一致。授權(quán)域名配置路徑:【公眾平臺(tái)->設(shè)置->公眾號(hào)設(shè)置->功能設(shè)置–>網(wǎng)頁(yè)授權(quán)域名】

Q:JSAPI調(diào)起支付接口報(bào)“該商戶暫不支持通過(guò)外部拉起微信完成支付”

A:JSAPI支付只能從微信瀏覽器內(nèi)發(fā)起支付請(qǐng)求



技術(shù)咨詢

文檔反饋