微信支付http://www.cnblogs.com/True_to_me/p/3565039.html
公众号支付有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+"¬ify_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+"¬ify_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+"×tamp="+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+"¬ify_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+"¬ify_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+"×tamp="+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的更多相关文章
- app使用微信支付成功后,点击返回到该app却跳到另外一个app去了
刚接手了公司iOS的两个APP, 现在碰到了这样一个问题: 有一台iPhone在一个APP中使用了微信支付,支付成功后,点击返回到该APP,结果却跳到了另外一个APP去了. 这两个APP都是公司开发的 ...
- 企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET
先看效果 1.本文演示的是微信[企业号]的H5页面微信支付 2.本项目基于开源微信框架WeiXinMPSDK开发:https://github.com/JeffreySu/WeiXinMPSDK 感谢 ...
- 微信支付(.NET版)
前段时间做了网页版微信支付,遇到很多问题,不过最终还是解决了,现在在这里记录下开发流程以及说明,给其他人一些参考. 一.准备工作 首先肯定得先要开通微信支付功能,之前开通微信支付需要三万的押金 ...
- 坑爹的微信支付v3,其实没有那么坑
http://www.cnblogs.com/zskbll/p/wxpay.html 研究微信开发一年多了,每个新接口,都会第一时间进行研究.微信支付开放很久,一直没机会接触到支付接口,等了好久终于从 ...
- ***CodeIgniter集成微信支付(转)
微信支付Native扫码支付模式二之CodeIgniter集成篇 http://www.cnblogs.com/24la/p/wxpay-native-qrcode-codeigniter.html ...
- iOS之微信支付
前言:下面介绍微信支付的开发流程的细节,图文并茂,你可以按照我的随笔流程过一遍代码.包你也学会了微信支付.而且支付也是面试常问的内容. 正文: 1.首先在开始使用微信支付之前,有一些东西是开发者必须要 ...
- 微信支付开发(1) JS API支付
关键字:微信支付 微信支付v3 jsapi支付 统一支付 Native支付 prepay_id 作者:方倍工作室原文: http://www.cnblogs.com/txw1958/p/wxpayv3 ...
- 微信支付开发(7) H5支付
关键字:微信支付 微信支付v3 H5支付 wap支付 prepay_id 作者:方倍工作室原文: http://www.cnblogs.com/txw1958/p/wxpayv3_h5.html 本文 ...
- Atitit 微信支付 支付结果通用通知
Atitit 微信支付 支付结果通用通知 Wechat hto sh ma 返回页面return_url - 熊佳佳的博客 d ,only notyfi url-... 接口链接 该链接是通过[统一 ...
随机推荐
- maven环境变的配置(复制自己看)
Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的软件项目管理工具. Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具.由于 Maven 的缺省构建 ...
- oracle dg 备库不同步主库数据
今天遇到一个数据库同步问题,主库被关闭,重启主库后,备库不能正常同步主库数据.只有当手动切换归档日志的时候,备库才能和主库一致. 这个问题的解决方法: 重启备库,重新应用归档日志. 操作步骤如下: / ...
- homework5 for java
- java连接mysql底层封装
package com.dao.db; import java.sql.Connection; import java.sql.SQLException; /** * 数据库连接层MYSQL * @a ...
- laydate日期控件
<!-- laydate 日期时间控件 下载地址 http://www.layui.com/laydate/ 这里用到版本为 layDate-v5.0.2 下载后将 laydate 文件夹放到项 ...
- Linux杂技
挂载光盘 mkdir /mnt/cdrom #建立挂载点 mount /dev/cdrom /mnt/cdrom/ #挂载光盘 更换YUM源: cd /etc/yum.repos.d/ 使网络yum源 ...
- thinkphp3.2 验证码的使用
验证码生成: public function verify(){ ob_clean(); $verify = new \Think\Verify; $verify->codeSet = '012 ...
- 【bzoj1391】[Ceoi2008]order 网络流最小割
原文地址:http://www.cnblogs.com/GXZlegend/p/6796937.html 题目描述 有N个工作,M种机器,每种机器你可以租或者买过来. 每个工作包括若干道工序,每道工序 ...
- [CQOI2012]局部极小值
题目链接 注意到\(4\times 7\)的矩阵的局部极小值最多只有8个,可以状压. 设\(f[i][sta]\)表示从小到大填数,当前填到\(i\),极小值的填充状态为\(sta\)的方案数. 考虑 ...
- WCF分布式开发步步为赢(12):WCF事务机制(Transaction)和分布式事务编程
今天我们继续学习WCF分布式开发步步为赢系列的12节:WCF事务机制(Transaction)和分布式事务编程.众所周知,应用系统开发过程中,事务是一个重要的概念.它是保证数据与服务可靠性的重要机制. ...