JSAPI支付是用戶在微信中打開商戶的H5頁面,商戶在H5頁面通過調用微信支付提供的JSAPI接口調起微信支付模塊完成支付
使用場景
用戶在微信公衆賬號(必須是服務號)內進入商家公衆號,打開某個H5頁面,完成支付
用戶的好友在朋友圈、聊天窗口等分享商家H5頁面連接,用戶點擊鏈接打開商家H5頁面,完成支付
將商戶H5頁面轉換成二維碼,用戶掃描二維碼後在微信瀏覽器中打開h5頁面後完成支付
JSAPI接口
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": "{{.AppId}}", //公衆號名稱,由商戶傳入
"timeStamp": "{{.TimeStamp}}",//時間戳,自1970年以來的秒數
"nonceStr": "{{.NonceStr}}",//隨機串
"package": "{{.Package}}",
"signType": "{{.SignType}}",//微信簽名方式:
"paySign": "{{.PaySign}}" //微信簽名
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
alert("支付成功");
}else if (res.err_msg == "get_brand_wcpay_request:cancel") {
alert("支付過程中用戶取消");
}else{
//支付失敗
alert(res.err_msg)
}
}
);
業務流程
開發實現
實現目標目標
打開網頁http://config.HOST/buy.html
,選購商品,最終打開http://config.HOST/jsapi.html
調起微信支付
JSAPI必須先用網頁授權的方式去獲取用戶的openid,在統一下單的時候需要,詳情可以查看官方文檔:網頁授權獲取獲取用戶基本信息
創建jsapipay包
創建文件夾jsapipay
設置網頁獲取用戶基本信息的授權域名
只有在授權域名下的鏈接才能獲取openid,所以第一步就去設置網頁授權目錄
假設我們網站的域名爲:www.qq.com,那麼久需要把網頁授權目錄設置爲www.qq.com
設置方法:登陸公衆平臺,在開發中中心,往下翻功能列表裏面有一項:網頁授權獲取用戶基本信息,點擊旁邊的修改按鈕即可,按照要求填入我們要設置的域名
在本節代碼裏面我們把域名保存在config.HOST
變量裏面
創建選購商品顯示頁面
創建buy.html
,點擊裏面的購買按鈕後,獲取code
並跳轉到支付頁面buy.html
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
<!DOCTYPE html>
<html>
<title>商家網頁</title>
<head>
<form class="editPart" action="{{.callbackurl}}">
<fieldset>
<legend>商家網頁</legend>
<p><label>商品金額1分錢測試</label></p>
<div class="lightEditor">
<iframe id="myFrame" class="editorFrame" style="height:162px;" frameborder="0px" tabindex=3></iframe>
</div>
</p>
<input type="submit" class="commentSubmit" value="點擊購買" />
</fieldset>
</form>
</body>
</html>
創建支付發起顯示頁面
創建jsapi.html
文件,實現:
- 實現對getBrandWCPayRequest接口的調用,從而調起微信支付
- 打印出我們使用的參數
代碼如下:
JSAPI支付一分錢
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
<script type="text/javascript">
//實現微信支付JS腳本
function pay() {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": "{{.AppId}}", //公衆號名稱,由商戶傳入
"timeStamp": "{{.TimeStamp}}",//時間戳,自1970年以來的秒數
"nonceStr": "{{.NonceStr}}",//隨機串
"package": "{{.Package}}",
"signType": "{{.SignType}}",//微信簽名方式:
"paySign": "{{.PaySign}}" //微信簽名
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
alert("支付成功");
}else if (res.err_msg == "get_brand_wcpay_request:cancel") {
alert("支付過程中用戶取消");
}else{
//支付失敗
alert(res.err_msg)
}
}
);
}
</script>
</head>
<body>
<!--打印出參數-->
<h1>微信jsapi支付 1分錢</h1>
<a>Appid: {{.AppId}}</a><br>
<a>TimeStamp: {{.TimeStamp}}</a><br>
<a>Nonce_str: {{.NonceStr}}</a><br>
<a>Package: {{.Package}}</a><br>
<a>SignType: {{.SignType}}</a><br>
<a>PaySign: {{.PaySign}}</a><br>
<button type="button" onclick="pay()">點擊微信支付</button>
</body>
</html>
getBrandWCPayRequest接口參數生成
創建文件jsapirequest.go
,實現
Jsapirequest
結構體:存儲getCPayReBrandWquest需要的參數,傳遞給jsapi.html
頁面
func (v *Jsapirequest) Signmd5()
函數:對Jsapirequest結構體中的非空參數進行微信支付簽名,並存儲簽名結果
代碼如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
package jsapipay
import (
"encoding/xml"
"wechatpaygolang/config"
"wechatpaygolang/tools"
)
//1.定義Jsapirequest結構體,存儲getBrandWCPayRequest接口要使用的參數
type Jsapirequest struct {
XMLName xml.Name `xml:"xml"`
AppId string `xml:"appId"` //公衆賬號ID
NonceStr string `xml:"nonceStr"` //隨機字符串
Package string `xml:"package"` //賬單類型
SignType string `xml:"signType"` //商戶號
TimeStamp string `xml:"timeStamp"` //對賬單日起
PaySign string `xml:"-"` //最終請求串
}
//2.對Jsapirequest的非空字段進行md5簽名,並存儲簽名結構
func (v *Jsapirequest) Signmd5() bool {
sign := tools.Wechatpay_SignMD5(*v, config.API_KEY)
v.PaySign = sign
return true
}
獲取openid
創建auth.go
文件,實現
Resultauth
結構體,存儲獲取到的y用戶基本新消息
func Getopenid(w http.ResponseWriter, r *http.Request) (openid string)
函數,根據code獲取openid
func getauthurl(callurl string) string
函數,生成網頁授權獲取code的url,code會回傳給callurl,注意這裏的callurl必須是
urlencode編碼
代碼實現
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
package jsapipay
import (
"fmt"
"wechatpaygolang/config"
"wechatpaygolang/tools"
)
type Resultauth struct {
Access_token string `json:"access_token"`
Expires_in int `json:"expires_in"`
Rfresh_token string `json:"rfresh_token"`
Openid string `json:"openid"`
Scope string `json:"scope"`
}
//根據code獲取openid
func Getopenid(code string) (openid string) {
r.ParseForm()
requestUrl := "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + config.APP_ID + "&secret=" + config.APP_SECRET + "&code=" + code + "&grant_type=authorization_code"
rebots := tools.Get(requestUrl)
var m Resultauth
err := tools.XmlDecodebytes(rebots, &m)
if err != nil {
fmt.Println("error:", err)
}
openid = m.Openid
fmt.Println("openid=" + openid)
return openid
}
// 獲取code
func getauthurl(url string) string {
str := "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx2b029c08a6232582&redirect_uri=" + url + "&response_type=code&scope=snsapi_base&state=test#wechat_redirect"
return str
}
創建jsapi.go
前面我們分別創建了2個html頁面,一個是表示選購頁面,一個是發起支付頁面,那麼決定顯示那個html頁面,並傳遞對應的參數進去,在jsapi.go
裏面實現
func Jsapi(w http.ResponseWriter, r *http.Request)
爲頁面入口函數,在這個函數裏面,進行顯示頁面的判斷和參數傳遞
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
package jsapipay
import (
"fmt"
"html/template"
"io/ioutil"
"net/http"
"os"
"wechatpaygolang/auth"
"wechatpaygolang/config"
"wechatpaygolang/tools"
"wechatpaygolang/unifiedorder"
)
func Jsapi(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
code := r.FormValue("code")
//沒有code·進入選購頁面
if code == "" {
path, _ := os.Getwd()
t, err := template.ParseFiles(path + "/jsapipay/buy.html")
fmt.Println(err)
m := map[string]string{}
m["callbackurl"] = getauthurl("http://" + config.HOST + "/jsapi")
da.Signmd5()
t.Execute(w, da)
} else {
//獲取openid
openid := auth.Getopenid(w, r)
//1.統一下單
v := &unifiedorder.Unifieldrequest{Appid: config.APP_ID, Mch_id: config.MCH_ID}
//支付金額,單位爲分
v.Total_fee = "1"
//商品說明
v.Body = "JSAPI"
//32位隨機字符串
v.Nonce_str = tools.Getnoncestr(32)
//商戶訂單號,此處也隨機生成
v.Out_trade_no = tools.Getnoncestr(32)
//發起支付的機器IP
v.Spbill_create_ip = "127.0.0.1"
//設置openid
v.Openid = "omL67jm0A1sKwystTq7WsU28MF_c"
//最終支付成功的通知地址
v.Notify_url = config.URL_UNIFIEDORDER_NOTIFYURL
//支付方式爲JSAPI
v.Trade_type = "JSAPI"
//對上面設置的字段進行簽名
v.Signmd5()
//把所有的有效字段組織爲xml格式
v.Xml()
//向統一下單接口發起請求,並把返回請求結果
res := v.Dorequest()
fmt.Println("下單結果=", res.ReponseXML)
fmt.Println("prepayid=", res.Prepay_id)
fmt.Println("========================================")
//打開支付網頁,並傳遞參數,包括傳遞我們上面統一下單獲取到的prepay_id
path, _ := os.Getwd()
t, err := template.ParseFiles(path + "/jsapipay/pay.html")
fmt.Println(err)
da := Jsapirequest{AppId: config.APP_ID}
da.Package = "prepay_id=" + res.Prepay_id
da.TimeStamp = tools.Time_stamp_seconds()
da.NonceStr = tools.Getnoncestr(32)
da.SignType = "MD5"
da.Signmd5()
t.Execute(w, da)
}
}
結果判定
在jsapi.html
裏面,根據判定結果,進行相應的處理
返回值 描述
get_brand_wcpay_request:ok 支付成功
get_brand_wcpay_request:cancel 支付過程中用戶取消
get_brand_wcpay_request:fail 支付失敗
和/jsapi地址關聯
在main.go
文件裏面
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
func rout(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
path := r.URL.Path
if path == "/helloworld" {
fmt.Println("被掃支付")
helloworld.HelloWorld(w, r)
} else if path == "/micropay" {
fmt.Println("被掃支付")
micropay.Micropay(w, r)
} else if path == "/jsapi" {
fmt.Println("被掃支付")
jsapi.Jsapi(w, r)
}
}
設置支付目錄
jsapi必須設置支付木有,只有在支付目錄下的頁面才能發起支付,否則會報錯,上異步我們已經確認了我們要訪問的地址爲/jsapi,假設我們的域
名爲www.qq.com,那麼這個時候我們的支付域名就是www.qq.com/jsapi,那麼我們就需要把www.paytest.com/設置爲支付目錄
設置方法:
登陸公衆平臺-微信支付-開發配置-JSAPI支付,添加支付目錄爲www.paytest.com/,注意添加的目錄的域名必須經過備案
同時可以設置測試目錄,測試目錄不需要備案,但必須把測試的微信號加入白名單,而且測試的支付鏈接只能在這個公衆號內打開
編譯測試
在微信裏面打開支付url,進行測試
異步通知
除了上面js接口裏面的結果判定,同時在統一下單的時候,我們填寫了一個notify_url
,我們同時會發送異步通知到這個地址,這個後面再說,因爲還有其他支付方式也會發送異步通知,所以作爲一個單獨模塊來說,這裏我們先隨便填一個,無所謂的。