公众号支付有2种支付方式:

JS API 支付:是指用户打开图文消息或者扫描二维码,在微信内置浏览器打开网页进行的支付。商户网页前端通过使用微信提供的 JS API,调用微信支付模块。这种方式,适合
需要在商户网页进行选购下单的购买流程。
  Native(原生)支付:是指商户组成符合 Native(原生)支付规则的 URL 链接,用户可通过点击该链接或者扫描对应的二维码直接进入微信支付模块(微信客户端界面),即可
进行支付。这种方式,适合无需选购直接支付的购买流程。

以上两种方式最大的区别是:是否需要经过网页调用!

交互原理:

客户是想做一个手机端的商城,所以选择JS API支付,通过网页调取微信支付。。

楼主第一次看过文档后,什么“支付签名(paySign)”啊,什么“package包”啊等等一些参数,反正似懂非懂的样子。楼主这人比较懒,不然也不会注册3年了,也就写了这么篇不入流的文章,楼主想啊像这些个大公司开放个啥接口的肯定会有demo。楼主的运气还真不错(PS:楼主可是为福利事业贡献了不少哦,咋就没这运气?),还真让楼主找到了,那心情肯定是比不上中500W的,嘿嘿。

<!DOCTYPE html>
<html>
<head>
<title>公众号支付测试网页</title>
<script language="javascript" src="http://res.mail.qq.com/mmr/static/lib/js/jquery.js"></script>
<script language="javascript" src="http://res.mail.qq.com/mmr/static/lib/js/lazyloadv3.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/sha1.js"></script>
<script Language="javascript">
//辅助函数
function Trim(str,is_global)
{
var result;
result = str.replace(/(^\s+)|(\s+$)/g,"");
if(is_global.toLowerCase()=="g") result = result.replace(/\s/g,"");
return result;
}
function clearBr(key)
{
key = Trim(key,"g");
key = key.replace(/<\/?.+?>/g,"");
key = key.replace(/[\r\n]/g, "");
return key;
} //获取随机数
function getANumber()
{
var date = new Date();
var times1970 = date.getTime();
var times = date.getDate() + "" + date.getHours() + "" + date.getMinutes() + "" + date.getSeconds();
var encrypt = times * times1970;
if(arguments.length == ){
return arguments[] + encrypt;
}else{
return encrypt;
} } //以下是package组包过程: var oldPackageString;//记住package,方便最后进行整体签名时取用 function getPartnerId()
{
return document.form1.partnerId.value;
} function getPartnerKey()
{
return "8934e7d15453e97507ef794cf7b0519d";
} function getPackage()
{
var banktype = "WX";
var body = document.form1.body.value;//商品名称信息,这里由测试网页填入。
var fee_type = "";//费用类型,这里1为默认的人民币
var input_charset = "GBK";//字符集,这里将统一使用GBK
var notify_url = "http://www.qq.com";//支付成功后将通知该地址
var out_trade_no = ""+getANumber();//订单号,商户需要保证该字段对于本商户的唯一性
var partner = getPartnerId();//测试商户号
var spbill_create_ip = "127.0.0.1";//用户浏览器的ip,这个需要在前端获取。这里使用127.0.0.1测试值
var total_fee = document.form1.totalFee.value;//总金额。
var partnerKey = getPartnerKey();//这个值和以上其他值不一样是:签名需要它,而最后组成的传输字符串不能含有它。这个key是需要商户好好保存的。 //首先第一步:对原串进行签名,注意这里不要对任何字段进行编码。这里是将参数按照key=value进行字典排序后组成下面的字符串,在这个字符串最后拼接上key=XXXX。由于这里的字段固定,因此只需要按照这个顺序进行排序即可。
var signString = "bank_type="+banktype+"&body="+body+"&fee_type="+fee_type+"&input_charset="+input_charset+"&notify_url="+notify_url+"&out_trade_no="+out_trade_no+"&partner="+partner+"&spbill_create_ip="+spbill_create_ip+"&total_fee="+total_fee+"&key="+partnerKey; var md5SignValue = ("" + CryptoJS.MD5(signString)).toUpperCase();
//然后第二步,对每个参数进行url转码,如果您的程序是用js,那么需要使用encodeURIComponent函数进行编码。 banktype = encodeURIComponent(banktype);
body=encodeURIComponent(body);
fee_type=encodeURIComponent(fee_type);
input_charset = encodeURIComponent(input_charset);
notify_url = encodeURIComponent(notify_url);
out_trade_no = encodeURIComponent(out_trade_no);
partner = encodeURIComponent(partner);
spbill_create_ip = encodeURIComponent(spbill_create_ip);
total_fee = encodeURIComponent(total_fee); //然后进行最后一步,这里按照key=value除了sign外进行字典序排序后组成下列的字符串,最后再串接sign=value
var completeString = "bank_type="+banktype+"&body="+body+"&fee_type="+fee_type+"&input_charset="+input_charset+"&notify_url="+notify_url+"&out_trade_no="+out_trade_no+"&partner="+partner+"&spbill_create_ip="+spbill_create_ip+"&total_fee="+total_fee;
completeString = completeString + "&sign="+md5SignValue; oldPackageString = completeString;//记住package,方便最后进行整体签名时取用 return completeString;
} //下面是app进行签名的操作: var oldTimeStamp ;//记住timestamp,避免签名时的timestamp与传入的timestamp时不一致
var oldNonceStr ; //记住nonceStr,避免签名时的nonceStr与传入的nonceStr不一致 function getAppId()
{
return document.form1.appId.value;
} function getAppKey()
{
return "2Wozy2aksie1puXUBpWD8oZxiD1DfQuEaiC7KcRATv1Ino3mdopKaPGQQ7TtkNySuAmCaDCrw4xhPY5qKTBl7Fzm0RgR3c0WaVYIXZARsxzHV2x7iwPPzOz94dnwPWSn";
} function getTimeStamp()
{
var timestamp=new Date().getTime();
var timestampstring = timestamp.toString();//一定要转换字符串
oldTimeStamp = timestampstring;
return timestampstring;
} function getNonceStr()
{
var $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var maxPos = $chars.length;
var noceStr = "";
for (i = ; i < ; i++) {
noceStr += $chars.charAt(Math.floor(Math.random() * maxPos));
}
oldNonceStr = noceStr;
return noceStr;
} function getSignType()
{
return "SHA1";
} function getSign()
{
var app_id = getAppId().toString();
var app_key = getAppKey().toString();
var nonce_str = oldNonceStr;
var package_string = oldPackageString;
var time_stamp = oldTimeStamp;
//第一步,对所有需要传入的参数加上appkey作一次key=value字典序的排序
var keyvaluestring = "appid="+app_id+"&appkey="+app_key+"&noncestr="+nonce_str+"&package="+package_string+"&timestamp="+time_stamp;
sign = CryptoJS.SHA1(keyvaluestring).toString();
return sign;
} </script>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<meta id="viewport" name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1; user-scalable=no;" /> <style> body { margin:;padding:;background:#eae9e6; }
body,p,table,td,th { font-size:14px;font-family:helvetica,Arial,Tahoma; }
h1 { font-family:Baskerville,HelveticaNeue-Bold,helvetica,Arial,Tahoma; }
a { text-decoration:none;color:#;} .container { }
.title { }
#content {padding:30px 20px 20px;color:#;box-shadow: 1px 4px #ccc; background:#f7f2ed; }
.seeAlso { padding:15px 20px 30px; } .headpic div { margin:20px ;}
.headpic img { display:block;} .title h1 { font-size:22px;font-weight:bold;padding:;margin:;line-height:1.2;color:#1f1f1f; }
.title p { color:#aaa;font-size:12px;margin:5px ;padding:;font-weight:bold;}
.pic { margin:20px ; }
.articlecontent img { display:block;clear:both;box-shadow:0px 1px 3px #; margin:5px auto;}
.articlecontent p { text-indent: 2em; font-family:Georgia,helvetica,Arial,Tahoma;line-height:1.4; font-size:16px; margin:20px ; } .seeAlso h3 { font-size:16px;color:#a5a5a5;}
.seeAlso ul { margin:;padding:; }
.seeAlso li { font-size:16px;list-style-type:none;border-top:1px solid #ccc;padding:2px ;}
.seeAlso li a { border-bottom:none;display:block;line-height:1.1; padding:13px ; } .clr{ clear:both;height:1px;overflow:hidden;} .fontSize1 .title h1 { font-size:20px; }
.fontSize1 .articlecontent p { font-size:14px; }
.fontSize1 .weibo .nickname,.fontSize1 .weibo .comment { font-size:11px; }
.fontSize1 .moreOperator { font-size:14px; } .fontSize2 .title h1 { font-size:22px; }
.fontSize2 .articlecontent p { font-size:16px; }
.fontSize2 .weibo .nickname,.fontSize2 .weibo .comment { font-size:13px; }
.fontSize2 .moreOperator { font-size:16px; } .fontSize3 .title h1 { font-size:24px; }
.fontSize3 .articlecontent p { font-size:18px; }
.fontSize3 .weibo .nickname,.fontSize3 .weibo .comment { font-size:15px; }
.fontSize3 .moreOperator { font-size:18px; } .fontSize4 .title h1 { font-size:26px; }
.fontSize4 .articlecontent p { font-size:20px; }
.fontSize4 .weibo .nickname,.fontSize4 .weibo .comment { font-size:16px; }
.fontSize4 .moreOperator { font-size:20px; } .jumptoorg { display:block;margin:16px 16px; }
.jumptoorg a { } .moreOperator a { color:#; } .moreOperator .share{ border-top:1px solid #ddd; } .moreOperator .share a{ display:block;border:1px solid #ccc;border-radius:4px;margin:20px ;border-bottom-style:solid;background:#f8f7f1;color:#; } .moreOperator .share a span{ display:block;padding:10px 10px;border-radius:4px;text-align:center;border-top:1px solid #eee;border-bottom:1px solid #eae9e3;font-weight:bold; } .moreOperator .share a:hover,
.moreOperator .share a:active { background:#efedea; }
@media only screen and (-webkit-min-device-pixel-ratio: ) {
}
</style>
<script language="javascript">
function auto_remove(img){
div=img.parentNode.parentNode;div.parentNode.removeChild(div);
img.onerror="";
return true;
} function changefont(fontsize){
if(fontsize < || fontsize > )return;
$('#content').removeClass().addClass('fontSize' + fontsize);
} // 当微信内置浏览器完成内部初始化后会触发WeixinJSBridgeReady事件。
document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
//公众号支付
jQuery('a#getBrandWCPayRequest').click(function(e){
WeixinJSBridge.invoke('getBrandWCPayRequest',{
"appId" : getAppId(), //公众号名称,由商户传入
"timeStamp" : getTimeStamp(), //时间戳
"nonceStr" : getNonceStr(), //随机串
"package" : getPackage(),//扩展包
"signType" : getSignType(), //微信签名方式:1.sha1
"paySign" : getSign() //微信签名
},function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {}
// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
//因此微信团队建议,当收到ok返回时,向商户后台询问是否收到交易成功的通知,若收到通知,前端展示交易成功的界面;若此时未收到通知,商户后台主动调用查询订单接口,查询订单的当前状态,并反馈给前端展示相应的界面。
}); }); WeixinJSBridge.log('yo~ ready.'); }, false) if(jQuery){
jQuery(function(){ var width = jQuery('body').width() * 0.87;
jQuery('img').error(function(){
var self = jQuery(this);
var org = self.attr('data-original1');
self.attr("src", org);
self.error(function(){
auto_remove(this);
});
});
jQuery('img').each(function(){
var self = jQuery(this);
var w = self.css('width');
var h = self.css('height');
w = w.replace('px', '');
h = h.replace('px', '');
if(w <= width){
return;
}
var new_w = width;
var new_h = Math.round(h * width / w);
self.css({'width' : new_w + 'px', 'height' : new_h + 'px'});
self.parents('div.pic').css({'width' : new_w + 'px', 'height' : new_h + 'px'});
});
});
}
</script>
</head>
<body> <form name="form1" target="_blank">
<table border="">
<TR><th>公众号ID</th> <th><INPUT value="wxf8b4f85f3a794e77" name="appId" id=""></th>
<tr><th>商户ID</th><th><INPUT value="" name="partnerId" id=""></th>
<TR><th>总金额</th><th><INPUT value= name="totalFee" id=""></th>
<TR><th>商品名</th><th><INPUT value="江诗丹顿" name="body" id=""></th>
</table>
</form>
<div class="WCPay">
<a id="getBrandWCPayRequest" href="javascript:void(0);"><h1 class="title">提交</h1></a>
</div> </body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>公众号支付测试网页</title>
<script language="javascript" src="http://res.mail.qq.com/mmr/static/lib/js/jquery.js"></script>
<script language="javascript" src="http://res.mail.qq.com/mmr/static/lib/js/lazyloadv3.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5.js"></script>
<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/sha1.js"></script>
<script Language="javascript">
//辅助函数
function Trim(str,is_global)
{
var result;
result = str.replace(/(^\s+)|(\s+$)/g,"");
if(is_global.toLowerCase()=="g") result = result.replace(/\s/g,"");
return result;
}
function clearBr(key)
{
key = Trim(key,"g");
key = key.replace(/<\/?.+?>/g,"");
key = key.replace(/[\r\n]/g, "");
return key;
} //获取随机数
function getANumber()
{
var date = new Date();
var times1970 = date.getTime();
var times = date.getDate() + "" + date.getHours() + "" + date.getMinutes() + "" + date.getSeconds();
var encrypt = times * times1970;
if(arguments.length == 1){
return arguments[0] + encrypt;
}else{
return encrypt;
} } //以下是package组包过程: var oldPackageString;//记住package,方便最后进行整体签名时取用 function getPartnerId()
{
return document.form1.partnerId.value;
} function getPartnerKey()
{
return "8934e7d15453e97507ef794cf7b0519d";
} function getPackage()
{
var banktype = "WX";
var body = document.form1.body.value;//商品名称信息,这里由测试网页填入。
var fee_type = "1";//费用类型,这里1为默认的人民币
var input_charset = "GBK";//字符集,这里将统一使用GBK
var notify_url = "http://www.qq.com";//支付成功后将通知该地址
var out_trade_no = ""+getANumber();//订单号,商户需要保证该字段对于本商户的唯一性
var partner = getPartnerId();//测试商户号
var spbill_create_ip = "127.0.0.1";//用户浏览器的ip,这个需要在前端获取。这里使用127.0.0.1测试值
var total_fee = document.form1.totalFee.value;//总金额。
var partnerKey = getPartnerKey();//这个值和以上其他值不一样是:签名需要它,而最后组成的传输字符串不能含有它。这个key是需要商户好好保存的。 //首先第一步:对原串进行签名,注意这里不要对任何字段进行编码。这里是将参数按照key=value进行字典排序后组成下面的字符串,在这个字符串最后拼接上key=XXXX。由于这里的字段固定,因此只需要按照这个顺序进行排序即可。
var signString = "bank_type="+banktype+"&body="+body+"&fee_type="+fee_type+"&input_charset="+input_charset+"&notify_url="+notify_url+"&out_trade_no="+out_trade_no+"&partner="+partner+"&spbill_create_ip="+spbill_create_ip+"&total_fee="+total_fee+"&key="+partnerKey; var md5SignValue = ("" + CryptoJS.MD5(signString)).toUpperCase();
//然后第二步,对每个参数进行url转码,如果您的程序是用js,那么需要使用encodeURIComponent函数进行编码。 banktype = encodeURIComponent(banktype);
body=encodeURIComponent(body);
fee_type=encodeURIComponent(fee_type);
input_charset = encodeURIComponent(input_charset);
notify_url = encodeURIComponent(notify_url);
out_trade_no = encodeURIComponent(out_trade_no);
partner = encodeURIComponent(partner);
spbill_create_ip = encodeURIComponent(spbill_create_ip);
total_fee = encodeURIComponent(total_fee); //然后进行最后一步,这里按照key=value除了sign外进行字典序排序后组成下列的字符串,最后再串接sign=value
var completeString = "bank_type="+banktype+"&body="+body+"&fee_type="+fee_type+"&input_charset="+input_charset+"&notify_url="+notify_url+"&out_trade_no="+out_trade_no+"&partner="+partner+"&spbill_create_ip="+spbill_create_ip+"&total_fee="+total_fee;
completeString = completeString + "&sign="+md5SignValue; oldPackageString = completeString;//记住package,方便最后进行整体签名时取用 return completeString;
} //下面是app进行签名的操作: var oldTimeStamp ;//记住timestamp,避免签名时的timestamp与传入的timestamp时不一致
var oldNonceStr ; //记住nonceStr,避免签名时的nonceStr与传入的nonceStr不一致 function getAppId()
{
return document.form1.appId.value;
} function getAppKey()
{
return "2Wozy2aksie1puXUBpWD8oZxiD1DfQuEaiC7KcRATv1Ino3mdopKaPGQQ7TtkNySuAmCaDCrw4xhPY5qKTBl7Fzm0RgR3c0WaVYIXZARsxzHV2x7iwPPzOz94dnwPWSn";
} function getTimeStamp()
{
var timestamp=new Date().getTime();
var timestampstring = timestamp.toString();//一定要转换字符串
oldTimeStamp = timestampstring;
return timestampstring;
} function getNonceStr()
{
var $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var maxPos = $chars.length;
var noceStr = "";
for (i = 0; i < 32; i++) {
noceStr += $chars.charAt(Math.floor(Math.random() * maxPos));
}
oldNonceStr = noceStr;
return noceStr;
} function getSignType()
{
return "SHA1";
} function getSign()
{
var app_id = getAppId().toString();
var app_key = getAppKey().toString();
var nonce_str = oldNonceStr;
var package_string = oldPackageString;
var time_stamp = oldTimeStamp;
//第一步,对所有需要传入的参数加上appkey作一次key=value字典序的排序
var keyvaluestring = "appid="+app_id+"&appkey="+app_key+"&noncestr="+nonce_str+"&package="+package_string+"&timestamp="+time_stamp;
sign = CryptoJS.SHA1(keyvaluestring).toString();
return sign;
} </script>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
<meta id="viewport" name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1; user-scalable=no;" /> <style> body { margin:0;padding:0;background:#eae9e6; }
body,p,table,td,th { font-size:14px;font-family:helvetica,Arial,Tahoma; }
h1 { font-family:Baskerville,HelveticaNeue-Bold,helvetica,Arial,Tahoma; }
a { text-decoration:none;color:#385487;} .container { }
.title { }
#content {padding:30px 20px 20px;color:#111;box-shadow:0 1px 4px #ccc; background:#f7f2ed; }
.seeAlso { padding:15px 20px 30px; } .headpic div { margin:20px 0 0;}
.headpic img { display:block;} .title h1 { font-size:22px;font-weight:bold;padding:0;margin:0;line-height:1.2;color:#1f1f1f; }
.title p { color:#aaa;font-size:12px;margin:5px 0 0;padding:0;font-weight:bold;}
.pic { margin:20px 0; }
.articlecontent img { display:block;clear:both;box-shadow:0px 1px 3px #999; margin:5px auto;}
.articlecontent p { text-indent: 2em; font-family:Georgia,helvetica,Arial,Tahoma;line-height:1.4; font-size:16px; margin:20px 0; } .seeAlso h3 { font-size:16px;color:#a5a5a5;}
.seeAlso ul { margin:0;padding:0; }
.seeAlso li { font-size:16px;list-style-type:none;border-top:1px solid #ccc;padding:2px 0;}
.seeAlso li a { border-bottom:none;display:block;line-height:1.1; padding:13px 0; } .clr{ clear:both;height:1px;overflow:hidden;} .fontSize1 .title h1 { font-size:20px; }
.fontSize1 .articlecontent p { font-size:14px; }
.fontSize1 .weibo .nickname,.fontSize1 .weibo .comment { font-size:11px; }
.fontSize1 .moreOperator { font-size:14px; } .fontSize2 .title h1 { font-size:22px; }
.fontSize2 .articlecontent p { font-size:16px; }
.fontSize2 .weibo .nickname,.fontSize2 .weibo .comment { font-size:13px; }
.fontSize2 .moreOperator { font-size:16px; } .fontSize3 .title h1 { font-size:24px; }
.fontSize3 .articlecontent p { font-size:18px; }
.fontSize3 .weibo .nickname,.fontSize3 .weibo .comment { font-size:15px; }
.fontSize3 .moreOperator { font-size:18px; } .fontSize4 .title h1 { font-size:26px; }
.fontSize4 .articlecontent p { font-size:20px; }
.fontSize4 .weibo .nickname,.fontSize4 .weibo .comment { font-size:16px; }
.fontSize4 .moreOperator { font-size:20px; } .jumptoorg { display:block;margin:16px 0 16px; }
.jumptoorg a { } .moreOperator a { color:#385487; } .moreOperator .share{ border-top:1px solid #ddd; } .moreOperator .share a{ display:block;border:1px solid #ccc;border-radius:4px;margin:20px 0;border-bottom-style:solid;background:#f8f7f1;color:#000; } .moreOperator .share a span{ display:block;padding:10px 10px;border-radius:4px;text-align:center;border-top:1px solid #eee;border-bottom:1px solid #eae9e3;font-weight:bold; } .moreOperator .share a:hover,
.moreOperator .share a:active { background:#efedea; }
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
}
</style>
<script language="javascript">
function auto_remove(img){
div=img.parentNode.parentNode;div.parentNode.removeChild(div);
img.onerror="";
return true;
} function changefont(fontsize){
if(fontsize < 1 || fontsize > 4)return;
$('#content').removeClass().addClass('fontSize' + fontsize);
} // 当微信内置浏览器完成内部初始化后会触发WeixinJSBridgeReady事件。
document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
//公众号支付
jQuery('a#getBrandWCPayRequest').click(function(e){
WeixinJSBridge.invoke('getBrandWCPayRequest',{
"appId" : getAppId(), //公众号名称,由商户传入
"timeStamp" : getTimeStamp(), //时间戳
"nonceStr" : getNonceStr(), //随机串
"package" : getPackage(),//扩展包
"signType" : getSignType(), //微信签名方式:1.sha1
"paySign" : getSign() //微信签名
},function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {}
// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
//因此微信团队建议,当收到ok返回时,向商户后台询问是否收到交易成功的通知,若收到通知,前端展示交易成功的界面;若此时未收到通知,商户后台主动调用查询订单接口,查询订单的当前状态,并反馈给前端展示相应的界面。
}); }); WeixinJSBridge.log('yo~ ready.'); }, false) if(jQuery){
jQuery(function(){ var width = jQuery('body').width() * 0.87;
jQuery('img').error(function(){
var self = jQuery(this);
var org = self.attr('data-original1');
self.attr("src", org);
self.error(function(){
auto_remove(this);
});
});
jQuery('img').each(function(){
var self = jQuery(this);
var w = self.css('width');
var h = self.css('height');
w = w.replace('px', '');
h = h.replace('px', '');
if(w <= width){
return;
}
var new_w = width;
var new_h = Math.round(h * width / w);
self.css({'width' : new_w + 'px', 'height' : new_h + 'px'});
self.parents('div.pic').css({'width' : new_w + 'px', 'height' : new_h + 'px'});
});
});
}
</script>
</head>
<body> <form name="form1" target="_blank">
<table border="1">
<TR><th>公众号ID</th> <th><INPUT value="wxf8b4f85f3a794e77" name="appId" id="1"></th>
<tr><th>商户ID</th><th><INPUT value="1900000109" name="partnerId" id="2"></th>
<TR><th>总金额</th><th><INPUT value=1 name="totalFee" id="3"></th>
<TR><th>商品名</th><th><INPUT value="江诗丹顿" name="body" id="4"></th>
</table>
</form>
<div class="WCPay">
<a id="getBrandWCPayRequest" href="javascript:void(0);"><h1 class="title">提交</h1></a>
</div> </body>
</html>

打开一看(楼主心里想TX你是多缺美工!),“提交”两字这么大,点一下试试,没反应?这不科学啊!立马找原因,当看到这句:“微信支付,是基于微信客户端提供的支付服务功能” ,楼主**(已和谐)了!放网站上用微信打开,这次有反应了!微信友情的提示我:“功能未授权”。。 这次知道是啥原因了,找客户沟通,原来合同快递还没到,保证金5W没交(现在只要2W了)。。

N天之后。。。。

这下测试能成功了,该怎么跟网站结合呢?不会直接把参数改了,然后让客户点提交吧?楼主想想这用户体验也太差了吧,客户肯定不认同。这问题纠结了楼主几天,百撕不得骑姐。有一天突然企业QQ一个讨论组的图标老闪,我就纳闷我没加过讨论组啊,打开正想喷(实际也真没喷过,能拉进讨论组都是好友,不过问题解不出来的时候确实很烦)的时候,人物列表那个头像怎么那么熟呢?那不我客户吗?瞬间一盆凉水从头到脚彻底没脾气了!A(TX商务人员):“你们的微信支付做好了没?”,我:“还没呢。”,A:"有什么困难吗?",我:“有,有一些地方不明白。”,A:"我帮你安排个技术支持吧?",楼主欣喜若狂啊,从看到这行信息到打出“好的”发出去绝对是没有超过1秒。。

之后楼主一帆风顺了,如鱼得水了,同事妹纸也变的水灵多了。。

<-------------------------------------------------------------------吐槽结束,华丽的分割线----------------------------------------------------------------->

以下是.NET版本的微信支付:

MD5Util类:

using System;
using System.Security.Cryptography;
using System.Text; namespace tenpayApp
{
/// <summary>
/// MD5Util 的摘要说明。
/// </summary>
public class MD5Util
{
public MD5Util()
{
//
// TODO: 在此处添加构造函数逻辑
//
} /** 获取大写的MD5签名结果 */
public static string GetMD5(string encypStr, string charset)
{
string retStr;
MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider(); //创建md5对象
byte[] inputBye;
byte[] outputBye; //使用GB2312编码方式把字符串转化为字节数组.
try
{
inputBye = Encoding.GetEncoding(charset).GetBytes(encypStr);
}
catch (Exception ex)
{
inputBye = Encoding.GetEncoding("GB2312").GetBytes(encypStr);
}
outputBye = m5.ComputeHash(inputBye); retStr = System.BitConverter.ToString(outputBye);
retStr = retStr.Replace("-", "").ToUpper();
return retStr;
}
}
}

RequestHandler类:

using System;
using System.Collections;
using System.Text;
using System.Web;
using System.Xml;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace tenpayApp
{
/**
'签名工具类
============================================================================/// <summary>
'api说明:
'init();
'初始化函数,默认给一些参数赋值。
'setKey(key_)'设置商户密钥
'createMd5Sign(signParams);字典生成Md5签名
'genPackage(packageParams);获取package包
'createSHA1Sign(signParams);创建签名SHA1
'parseXML();输出xml
'getDebugInfo(),获取debug信息
*
* ============================================================================
*/
public class RequestHandler
{ public RequestHandler(HttpContext httpContext)
{
parameters = new Hashtable(); this.httpContext = httpContext; }
/** 密钥 */
private string key; protected HttpContext httpContext; /** 请求的参数 */
protected Hashtable parameters; /** debug信息 */
private string debugInfo; /** 初始化函数 */
public virtual void init()
{
}
/** 获取debug信息 */
public String getDebugInfo()
{
return debugInfo;
}
/** 获取密钥 */
public String getKey()
{
return key;
} /** 设置密钥 */
public void setKey(string key)
{
this.key = key;
} /** 设置参数值 */
public void setParameter(string parameter, string parameterValue)
{
if (parameter != null && parameter != "")
{
if (parameters.Contains(parameter))
{
parameters.Remove(parameter);
} parameters.Add(parameter, parameterValue);
}
} //获取package带参数的签名包
public string getRequestURL()
{
this.createSign();
StringBuilder sb = new StringBuilder();
ArrayList akeys=new ArrayList(parameters.Keys);
akeys.Sort();
foreach(string k in akeys)
{
string v = (string)parameters[k];
if(null != v && "key".CompareTo(k) != )
{
sb.Append(k + "=" + TenpayUtil.UrlEncode(v, getCharset()) + "&");
}
} //去掉最后一个&
if(sb.Length > )
{
sb.Remove(sb.Length-, );
} return sb.ToString(); } //创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 protected virtual void createSign()
{
StringBuilder sb = new StringBuilder(); ArrayList akeys=new ArrayList(parameters.Keys);
akeys.Sort(); foreach(string k in akeys)
{
string v = (string)parameters[k];
if(null != v && "".CompareTo(v) !=
&& "sign".CompareTo(k) != && "key".CompareTo(k) != )
{
sb.Append(k + "=" + v + "&");
}
} sb.Append("key=" + this.getKey());
string sign = MD5Util.GetMD5(sb.ToString(), getCharset()).ToUpper(); this.setParameter("sign", sign); //debug信息
this.setDebugInfo(sb.ToString() + " => sign:" + sign);
} //创建package签名
public virtual string createMd5Sign()
{
StringBuilder sb = new StringBuilder();
ArrayList akeys=new ArrayList(parameters.Keys);
akeys.Sort(); foreach(string k in akeys)
{
string v = (string)parameters[k];
if(null != v && "".CompareTo(v) !=
&& "sign".CompareTo(k) != && "".CompareTo(v) != )
{
sb.Append(k + "=" + v + "&");
}
}
string sign = MD5Util.GetMD5(sb.ToString(), getCharset()).ToLower(); this.setParameter("sign", sign);
return sign;
} //创建sha1签名
public string createSHA1Sign()
{
StringBuilder sb = new StringBuilder();
ArrayList akeys = new ArrayList(parameters.Keys);
akeys.Sort(); foreach (string k in akeys)
{
string v = (string)parameters[k];
if (null != v && "".CompareTo(v) !=
&& "sign".CompareTo(k) != && "key".CompareTo(k) != )
{
if(sb.Length==)
{
sb.Append(k + "=" + v);
}
else{
sb.Append("&" + k + "=" + v);
}
}
}
string paySign = SHA1Util.getSha1(sb.ToString()).ToString().ToLower(); //debug信息
this.setDebugInfo(sb.ToString() + " => sign:" + paySign);
return paySign;
} //输出XML
public string parseXML()
{
StringBuilder sb = new StringBuilder();
sb.Append("<xml>");
foreach (string k in parameters.Keys)
{
string v = (string)parameters[k];
if (Regex.IsMatch(v, @"^[0-9.]$"))
{ sb.Append("<" + k + ">" + v + "</" + k + ">");
}
else
{
sb.Append("<" + k + "><![CDATA[" + v + "]]></" + k + ">");
} }
sb.Append("</xml>");
return sb.ToString();
} /** 设置debug信息 */
public void setDebugInfo(String debugInfo)
{
this.debugInfo = debugInfo;
} public Hashtable getAllParameters()
{
return this.parameters;
} protected virtual string getCharset()
{
return this.httpContext.Request.ContentEncoding.BodyName;
}
}
}

ResponseHandler类:

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Text;
using System.Web;
using System.Xml; namespace tenpayApp
{ /**
'============================================================================
'api说明:
'getKey()/setKey(),获取/设置密钥
'getParameter()/setParameter(),获取/设置参数值
'getAllParameters(),获取所有参数
'isTenpaySign(),是否正确的签名,true:是 false:否
'isWXsign(),是否正确的签名,true:是 false:否
' * isWXsignfeedback判断微信维权签名
' *getDebugInfo(),获取debug信息
'============================================================================
*/ public class ResponseHandler
{
// 密钥
private string key; // appkey
private string appkey; //xmlMap
private Hashtable xmlMap; // 应答的参数
protected Hashtable parameters; //debug信息
private string debugInfo;
//原始内容
protected string content; private string charset = "gb2312"; //参与签名的参数列表
private static string SignField = "appid,appkey,timestamp,openid,noncestr,issubscribe"; protected HttpContext httpContext; //初始化函数
public virtual void init()
{
} //获取页面提交的get和post参数
public ResponseHandler(HttpContext httpContext)
{
parameters = new Hashtable();
xmlMap = new Hashtable(); this.httpContext = httpContext;
NameValueCollection collection;
//post data
if (this.httpContext.Request.HttpMethod == "POST")
{
collection = this.httpContext.Request.Form;
foreach (string k in collection)
{
string v = (string)collection[k];
this.setParameter(k, v);
}
}
//query string
collection = this.httpContext.Request.QueryString;
foreach (string k in collection)
{
string v = (string)collection[k];
this.setParameter(k, v);
}
if (this.httpContext.Request.InputStream.Length > )
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(this.httpContext.Request.InputStream);
XmlNode root = xmlDoc.SelectSingleNode("xml");
XmlNodeList xnl = root.ChildNodes; foreach (XmlNode xnf in xnl)
{
xmlMap.Add(xnf.Name, xnf.InnerText);
}
}
} /** 获取密钥 */
public string getKey()
{ return key;} /** 设置密钥 */
public void setKey(string key, string appkey)
{
this.key = key;
this.appkey = appkey;
} /** 获取参数值 */
public string getParameter(string parameter)
{
string s = (string)parameters[parameter];
return (null == s) ? "" : s;
} /** 设置参数值 */
public void setParameter(string parameter,string parameterValue)
{
if(parameter != null && parameter != "")
{
if(parameters.Contains(parameter))
{
parameters.Remove(parameter);
} parameters.Add(parameter,parameterValue);
}
} /** 是否财付通签名,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
* @return boolean */
public virtual Boolean isTenpaySign()
{
StringBuilder sb = new StringBuilder(); ArrayList akeys=new ArrayList(parameters.Keys);
akeys.Sort(); foreach(string k in akeys)
{
string v = (string)parameters[k];
if(null != v && "".CompareTo(v) !=
&& "sign".CompareTo(k) != && "key".CompareTo(k) != )
{
sb.Append(k + "=" + v + "&");
}
} sb.Append("key=" + this.getKey());
string sign = MD5Util.GetMD5(sb.ToString(), getCharset()).ToLower();
this.setDebugInfo(sb.ToString() + " => sign:" + sign);
//debug信息
return getParameter("sign").ToLower().Equals(sign);
} //判断微信签名
public virtual Boolean isWXsign()
{
StringBuilder sb = new StringBuilder();
Hashtable signMap = new Hashtable(); foreach (string k in xmlMap.Keys)
{
if (k != "SignMethod" && k != "AppSignature")
{
signMap.Add(k.ToLower(), xmlMap[k]);
}
}
signMap.Add("appkey", this.appkey); ArrayList akeys = new ArrayList(signMap.Keys);
akeys.Sort(); foreach (string k in akeys)
{
string v = (string)signMap[k];
if (sb.Length == )
{
sb.Append(k + "=" + v);
}
else
{
sb.Append("&" + k + "=" + v);
}
} string sign = SHA1Util.getSha1(sb.ToString()).ToString().ToLower(); this.setDebugInfo(sb.ToString() + " => SHA1 sign:" + sign); return sign.Equals(xmlMap["AppSignature"]); } //判断微信维权签名
public virtual Boolean isWXsignfeedback()
{
StringBuilder sb = new StringBuilder();
Hashtable signMap = new Hashtable(); foreach (string k in xmlMap.Keys)
{
if (SignField.IndexOf(k.ToLower()) != -)
{
signMap.Add(k.ToLower(), xmlMap[k]);
}
}
signMap.Add("appkey", this.appkey); ArrayList akeys = new ArrayList(signMap.Keys);
akeys.Sort(); foreach (string k in akeys)
{
string v = (string)signMap[k];
if ( sb.Length == )
{
sb.Append(k + "=" + v);
}
else
{
sb.Append("&" + k + "=" + v);
}
} string sign = SHA1Util.getSha1(sb.ToString()).ToString().ToLower(); this.setDebugInfo(sb.ToString() + " => SHA1 sign:" + sign); return sign.Equals( xmlMap["AppSignature"] ); } /** 获取debug信息 */
public string getDebugInfo()
{ return debugInfo;} /** 设置debug信息 */
protected void setDebugInfo(String debugInfo)
{ this.debugInfo = debugInfo;} protected virtual string getCharset()
{
return this.httpContext.Request.ContentEncoding.BodyName; } }
}

SHA1Util:

using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography; namespace tenpayApp
{
class SHA1Util
{
public static String getSha1(String str)
{
//建立SHA1对象
SHA1 sha = new SHA1CryptoServiceProvider();
//将mystr转换成byte[]
ASCIIEncoding enc = new ASCIIEncoding();
byte[] dataToHash = enc.GetBytes(str);
//Hash运算
byte[] dataHashed = sha.ComputeHash(dataToHash);
//将运算结果转换成string
string hash = BitConverter.ToString(dataHashed).Replace("-", "");
return hash;
}
}
}

TenpayUtil:

using System;
using System.Text;
using System.Web;
namespace tenpayApp
{
/// <summary>
/// TenpayUtil 的摘要说明。
/// 配置文件
/// </summary>
public class TenpayUtil
{
public static string tenpay = "";
public static string partner = ""; //商户号
public static string key = ""; //密钥
public static string appid = "";//appid
public static string appkey = "";//paysignkey(非appkey)
public static string tenpay_notify = "http://localhost/payNotifyUrl.aspx"; //支付完成后的回调处理页面,*替换成notify_url.asp所在路径 public TenpayUtil()
{ }
public static string getNoncestr()
{
Random random = new Random();
return MD5Util.GetMD5(random.Next().ToString(), "GBK");
} public static string getTimestamp()
{
TimeSpan ts = DateTime.UtcNow - new DateTime(, , , , , , );
return Convert.ToInt64(ts.TotalSeconds).ToString();
} /** 对字符串进行URL编码 */
public static string UrlEncode(string instr, string charset)
{
//return instr;
if(instr == null || instr.Trim() == "")
return "";
else
{
string res; try
{
res = HttpUtility.UrlEncode(instr,Encoding.GetEncoding(charset)); }
catch (Exception ex)
{
res = HttpUtility.UrlEncode(instr,Encoding.GetEncoding("GB2312"));
} return res;
}
} /** 对字符串进行URL解码 */
public static string UrlDecode(string instr, string charset)
{
if(instr == null || instr.Trim() == "")
return "";
else
{
string res; try
{
res = HttpUtility.UrlDecode(instr,Encoding.GetEncoding(charset)); }
catch (Exception ex)
{
res = HttpUtility.UrlDecode(instr,Encoding.GetEncoding("GB2312"));
} return res; }
} /** 取时间戳生成随即数,替换交易单号中的后10位流水号 */
public static UInt32 UnixStamp()
{
TimeSpan ts = DateTime.Now - TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(, , ));
return Convert.ToUInt32(ts.TotalSeconds);
}
/** 取随机数 */
public static string BuildRandomStr(int length)
{
Random rand = new Random(); int num = rand.Next(); string str = num.ToString(); if(str.Length > length)
{
str = str.Substring(,length);
}
else if(str.Length < length)
{
int n = length - str.Length;
while(n > )
{
str.Insert(, "");
n--;
}
} return str;
} }
}

页面代码:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;
using tenpayApp;
//=================================
//JSAPI支付
//=================================
public partial class _Default : System.Web.UI.Page
{
public String appId = TenpayUtil.appid;
public String timeStamp = "";
public String nonceStr = "";
public String packageValue = "";
public String paySign = ""; protected void Page_Load(object sender, EventArgs e)
{
string sp_billno = Request["order_no"];
//当前时间 yyyyMMdd
string date = DateTime.Now.ToString("yyyyMMdd"); if (null == sp_billno)
{
//生成订单10位序列号,此处用时间和随机数生成,商户根据自己调整,保证唯一
sp_billno = DateTime.Now.ToString("HHmmss") + TenpayUtil.BuildRandomStr();
}
else
{
sp_billno = Request["order_no"].ToString();
} sp_billno = TenpayUtil.partner + sp_billno; //创建支付应答对象
RequestHandler packageReqHandler = new RequestHandler(Context);
//初始化
packageReqHandler.init(); //设置package订单参数
packageReqHandler.setParameter("partner", TenpayUtil.partner); //商户号
packageReqHandler.setParameter("fee_type", ""); //币种,1人民币
packageReqHandler.setParameter("input_charset", "GBK");
packageReqHandler.setParameter("out_trade_no", sp_billno); //商家订单号
packageReqHandler.setParameter("total_fee", ""); //商品金额,以分为单位(money * 100).ToString()
packageReqHandler.setParameter("notify_url", TenpayUtil.tenpay_notify); //接收财付通通知的URL
packageReqHandler.setParameter("body", "JSAPIdemo"); //商品描述
packageReqHandler.setParameter("spbill_create_ip", Page.Request.UserHostAddress); //用户的公网ip,不是商户服务器IP //获取package包
packageValue = packageReqHandler.getRequestURL(); //调起微信支付签名
timeStamp = TenpayUtil.getTimestamp();
nonceStr = TenpayUtil.getNoncestr(); //设置支付参数
RequestHandler paySignReqHandler = new RequestHandler(Context);
paySignReqHandler.setParameter("appid", appId);
paySignReqHandler.setParameter("appkey", TenpayUtil.appkey);
paySignReqHandler.setParameter("noncestr", nonceStr);
paySignReqHandler.setParameter("timestamp", timeStamp);
paySignReqHandler.setParameter("package", packageValue);
paySign = paySignReqHandler.createSHA1Sign(); //获取debug信息,建议把请求和debug信息写入日志,方便定位问题
//string pakcageDebuginfo = packageReqHandler.getDebugInfo();
//Response.Write("<br/>pakcageDebuginfo:" + pakcageDebuginfo + "<br/>");
//string paySignDebuginfo = paySignReqHandler.getDebugInfo();
//Response.Write("<br/>paySignDebuginfo:" + paySignDebuginfo + "<br/>"); }
}

微信支付http://www.cnblogs.com/True_to_me/p/3565039.html的更多相关文章

  1. app使用微信支付成功后,点击返回到该app却跳到另外一个app去了

    刚接手了公司iOS的两个APP, 现在碰到了这样一个问题: 有一台iPhone在一个APP中使用了微信支付,支付成功后,点击返回到该APP,结果却跳到了另外一个APP去了. 这两个APP都是公司开发的 ...

  2. 企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET

    先看效果 1.本文演示的是微信[企业号]的H5页面微信支付 2.本项目基于开源微信框架WeiXinMPSDK开发:https://github.com/JeffreySu/WeiXinMPSDK 感谢 ...

  3. 微信支付(.NET版)

    前段时间做了网页版微信支付,遇到很多问题,不过最终还是解决了,现在在这里记录下开发流程以及说明,给其他人一些参考. 一.准备工作     首先肯定得先要开通微信支付功能,之前开通微信支付需要三万的押金 ...

  4. 坑爹的微信支付v3,其实没有那么坑

    http://www.cnblogs.com/zskbll/p/wxpay.html 研究微信开发一年多了,每个新接口,都会第一时间进行研究.微信支付开放很久,一直没机会接触到支付接口,等了好久终于从 ...

  5. ***CodeIgniter集成微信支付(转)

    微信支付Native扫码支付模式二之CodeIgniter集成篇  http://www.cnblogs.com/24la/p/wxpay-native-qrcode-codeigniter.html ...

  6. iOS之微信支付

    前言:下面介绍微信支付的开发流程的细节,图文并茂,你可以按照我的随笔流程过一遍代码.包你也学会了微信支付.而且支付也是面试常问的内容. 正文: 1.首先在开始使用微信支付之前,有一些东西是开发者必须要 ...

  7. 微信支付开发(1) JS API支付

    关键字:微信支付 微信支付v3 jsapi支付 统一支付 Native支付 prepay_id 作者:方倍工作室原文: http://www.cnblogs.com/txw1958/p/wxpayv3 ...

  8. 微信支付开发(7) H5支付

    关键字:微信支付 微信支付v3 H5支付 wap支付 prepay_id 作者:方倍工作室原文: http://www.cnblogs.com/txw1958/p/wxpayv3_h5.html 本文 ...

  9. Atitit 微信支付 支付结果通用通知

    Atitit 微信支付 支付结果通用通知 Wechat hto sh ma  返回页面return_url - 熊佳佳的博客 d ,only notyfi url-... 接口链接 该链接是通过[统一 ...

随机推荐

  1. 【转】hexo博客图片问题

    1.首先确认_config.yml 中有 post_asset_folder:true. Hexo 提供了一种更方便管理 Asset 的设定:post_asset_folder 当您设置post_as ...

  2. @section script{}的使用

    1,MVC视图中,JS代码被放在下面的Razor代码中(@section script{}) 2,这样做的好处是:在视图进行JS编码时是一个很好 的实践,在共享视图(_layout.cshtml),存 ...

  3. 【转】GOOGLE-PROTOBUF与FLATBUFFERS数据的序列化和反序列化

    转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/unity3d-game/1607.html  关于Protobuf 通过本文的转载和分享的相关链接,足够 ...

  4. CentOS7中rpm,yum软件安装命令

    RPM包常用安装位置说明 /etc/                   配置文件安装目录 /usr/bin/               可执行的命令安装目录 /usr/lib/           ...

  5. OSCache页面缓存的使用

    完成项目时,为了减少对数据库的频繁操作,引出了缓存,缓存分为以下几种: 1.一级缓存 一级缓存的存储域是session,作用于单个的dao 2.二级缓存 二级缓存的存储域是sessionFactory ...

  6. Hadoop上配置Hbase数据库

    已有环境: 1. Ubuntu:14.04.2 2.jdk: 1.8.0_45 3.hadoop:2.6.0 4.hBase:1.0.0 详细过程: 1.下载最新的Hbase,这里我下载的是hbase ...

  7. SRM710 div1 MagicNim(博弈论)

    题目大意: 给出n+1堆石子,前n堆石子的数量是a[i],最后一堆只有1个石子,但是具有魔力 拿走该石子的一方可以选择接下来是进行普通的Nim游戏还是anti-nim游戏 问是先手必胜还是必败 首先拿 ...

  8. poj3375 Network Connection

    Description There are \(M\) network interfaces in the wall of aisle of library. And \(N\) computers ...

  9. 停课day5

    一转眼,已经停课五天了. 高二大佬们已经都走了,在机房里面呆着,有时感觉很孤寂. 但是为了能学好竞赛,这些都是在所不惜的. 好像多打打比赛啊,可是cf要FQ,洛谷之类的比赛还不勤. 哎,先去学一发SP ...

  10. [学习笔记]扩展LUCAS定理

    可以先做这个题[SDOI2010]古代猪文 此算法和LUCAS定理没有半毛钱关系. [模板]扩展卢卡斯 不保证P是质数. $C_n^m=\frac{n!}{m!(n-m)!}$ 麻烦的是分母. 如果互 ...