公众号支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。应用场景有:
- ◆ 用户在微信公众账号内进入商家公众号,打开某个主页面,完成支付
- ◆ 用户的好友在朋友圈、聊天窗口等分享商家页面连接,用户点击链接打开商家页面,完成支付
- ◆ 将商户页面转换成二维码,用户扫描二维码后在微信浏览器中打开页面后完成支付
官方DEMO
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_3
由于微信5.0版本后才加入微信支付模块,低版本用户调用微信支付功能将无效。因此,建议商户通过user agent来确定用户当前的版本号后再调用支付接口。
在微信浏览器里面打开H5网页中执行JS调起支付。接口输入输出数据格式为JSON。
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> //必须引用 <script>
//判断微信的版本
$(function () {
var wechatInfo = navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
if (wechatInfo[1] < "5.0") {
alert("微信支付版本过低!请升级最新版本");
}
})
</script>
<script type="text/javascript">
//if(!(/MicroMessenger/i.test(navigator.userAgent)))
//{
// document.body.innerHTML="请在微信打开此链接";
//}
// 注意:所有的JS接口只能在公众号绑定的域名下调用,公众号开发者需要先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”。
wx.config({
debug: true,
appId: '<%=AppID%>',
timestamp: '<%=wx.timestamp%>',
nonceStr: '<%=wx.noncestr%>',
signature: '<%=wx.signature%>',
jsApiList: [
'chooseWXPay'
]
});
wx.ready(function () {
//支付接口
wx.chooseWXPay({
appId: '<%=AppID%>',
timestamp: '<%=wx.timestamp %>', //支付签名的时间戳,注意JSSDK中所有的使用timestamp字段均为小写,但新版支付后台生成的签名timeStamp字段名需要大写S字符。
nonceStr: '<%=wx.noncestr %>', //支付签名随机,不能产生超过32位
package: 'prepay_id=<%=prepay_id %>', //统一支付接口返回的prepay_id参数值
signType: 'MD5', //默认签名SHA1但新版要传MD5
paySign: '<%=paySign %>', //支付签名
success: function (res) {
//当充值成功的时候不返回Success成功
//注:如果当用户当支付完成后点击其他页面没有返回此页面,那么就不会执行Success。
//为了保险起见,在后台的回调参数来处理充值成功的逻辑
}, cancel: function () { window.history.back(-1); }, error: function (e) { alert("支付失败"); window.history.back(-1); } }); // 2.2 监听“分享到朋友圈”按钮点击、自定义分享内容及分享结果接口 wx.error(function (res) { // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。 alert("errorMSG:" + res); }); }); </script>
服务端
protected void Page_Load(object sender, EventArgs e)
{
Total_price =100; //价格
//因为jsapi_ticket票据获取次数有限,所以缓存7200秒
if (HttpContext.Current.Session["jsapi"] == null) //
{
//acess_token 同样获取次数有限,所以缓存7200秒
string actoken = "";
if (HttpContext.Current.Session["token"] != null)
{
actoken = HttpContext.Current.Session["token"] as string;
}
else
{
//获取access_tokenAccess_token ac = au.GetAcess_token(AppID, AppSecret);
if (ac != null)
{
HttpContext.Current.Session["token"] = ac.access_token;
actoken = ac.access_token;
// HttpContext.Current.Session.Timeout = 72000;
}
}
//获取JSAPI的票据
WeiXinJsapi_ticket jsapi = au.GetTickect(actoken);
WeiXinJsapi_ticketJs jsapis = new WeiXinJsapi_ticketJs();
#region 可以去掉
jsapis.errcode = jsapi.errcode;
jsapis.errmsg = jsapi.errmsg;
jsapis.expires_in = jsapi.expires_in;
jsapis.ticket = jsapi.ticket;
#endregion
//获取时间戳
long time = au.GetTimeStamp();
//获取随机字符串
string noncestr = au.GetNoncestr();
jsapis.noncestr = noncestr;
string signature = au.GetSignature(jsapis.ticket, noncestr, time, HttpContext.Current.Request.Url.ToString(), "");//必须动态获取
jsapis.timestamp = time.ToString();
jsapis.signature = signature;
HttpContext.Current.Session["jsapi"] = jsapis;
HttpContext.Current.Session.Timeout = 72000;
string mss = JsonSerializeUtils.JsSerializer(jsapis);
wx = jsapis;
}
else
{
wx = HttpContext.Current.Session["jsapi"] as WeiXinJsapi_ticketJs;
string mss = JsonSerializeUtils.JsSerializer(wx);
long time = au.GetTimeStamp();
string noncestr = au.GetNoncestr();
wx.noncestr = noncestr;
string signature = au.GetSignature(wx.ticket, noncestr, time, HttpContext.Current.Request.Url.ToString(), "");//必须动态获取
wx.timestamp = time.ToString();
wx.signature = signature;
}
GetprepayIdAndpaySign();
}
}
public string paySign = "";//paySign public string RdCode = "";//随机数 public string prepay_id = "";//package中prepay_id的值
public string key = "haobangren201691wuzhenghuitestpa";
/// <summary>
/// 获取prepayId值方法
/// </summary>
public void GetprepayIdAndpaySign()
{
//公众账号ID
string appid = AppID;
//商品描述
string OrderCode = DateTime.Now.ToString("yyyyMMddHHmmss");
string body = "订单号:" + OrderCode;
//商户号
string mch_id = "1384081602";
//随机字符串
string nonce_str = wx.noncestr ;
//通知地址-接收微信支付成功通知 注意不能带参数
string notify_url = "http://www.haobangren.com/WebChart/Member/Pays.aspx?action=add";
//用户标识 -用户在商户appid下的唯一标识
string openid = userBll.GetUser(LoginUserID).OpenID;
//商户订单号
string out_trade_no = OrderCode;
out_trade_nos = OrderCode;
//下单IP
string spbill_create_ip = WebCommon.GetClientIP();
//总金额 分为单位
int total_fee = Total_price;
//交易类型 -JSAPI、NATIVE、APP 如果是生成二维码请填写NATIVE
string trade_type = "JSAPI";
//微信签名
string tmpStr = "appid=" + appid + "&body=" + body + "&mch_id=" + mch_id + "&nonce_str=" + nonce_str + "¬ify_url=" + notify_url + "&openid=" + openid + "&out_trade_no=" + out_trade_no + "&spbill_create_ip=" + spbill_create_ip + "&total_fee=" + total_fee + "&trade_type=" + trade_type + "&key=" + key + "";
string Getprepay_idSign = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "MD5").ToUpper();
string url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
string xml = "<xml>";
xml += "<openid>" + userBll.GetUser(LoginUserID).OpenID + "</openid>";
xml += "<body>" + body + "</body>";
xml += "<mch_id>" + mch_id + "</mch_id>";
xml += "<nonce_str>" + nonce_str + "</nonce_str>";
xml += "<notify_url>" + notify_url + "</notify_url>";
xml += "<openid>" + openid + "</openid>";
xml += "<out_trade_no>" + out_trade_no + "</out_trade_no>";
xml += "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>";
xml += "<appid>" + AppID + "</appid>";
xml += "<total_fee>" + total_fee + "</total_fee>";
xml += "<trade_type>" + trade_type + "</trade_type>";
xml += "<sign>" + Getprepay_idSign + "</sign>";
xml += "</xml>";
DesignHawk.Common.LogHelper.WriteLog(null, "XML:" + xml);
string v = PostWebRequests(url, xml);
prepay_id = v;
paySign = "";
string v_tmpStr = "appId=" + appid + "&nonceStr=" + wx.noncestr + "&package=prepay_id=" + v + "&signType=MD5&timeStamp=" + wx.timestamp + "&key="+ key + "";
paySign = FormsAuthentication.HashPasswordForStoringInConfigFile(v_tmpStr, "MD5").ToUpper();
}
/// <summary>
/// 获取prepay_id
/// </summary>
/// <param name="postUrl"></param>
/// <param name="menuInfo"></param>
/// <returns></returns>
public string PostWebRequests(string postUrl, string menuInfo)
{
string returnValue = string.Empty;
try
{
byte[] byteData = Encoding.UTF8.GetBytes(menuInfo);
Uri uri = new Uri(postUrl);
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(uri);
webReq.Method = "POST";
webReq.ContentType = "application/x-www-form-urlencoded";
webReq.ContentLength = byteData.Length;
//定义Stream信息
Stream stream = webReq.GetRequestStream();
stream.Write(byteData, 0, byteData.Length);
stream.Close();
//获取返回信息
HttpWebResponse response = (HttpWebResponse)webReq.GetResponse();
StreamReader streamReader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
returnValue = streamReader.ReadToEnd();
//关闭信息
streamReader.Close();
response.Close();
stream.Close();
XmlDocument doc = new XmlDocument();
doc.LoadXml(returnValue);
XmlNodeList list = doc.GetElementsByTagName("xml");
XmlNode xn = list[0];
string prepay_ids = xn.SelectSingleNode("//prepay_id").InnerText;
return prepay_ids;
//如果是二维码扫描,请返回下边的code_url,然后自己再更具内容生成二维码即可
//string code_url = xn.SelectSingleNode("//prepay_id").InnerText;
//return code_url;
}
catch (Exception ex)
{
return "";
}
}