真实的微信公众号支付开发经历,在这里说句实话,微信的公众号支付开发文档写的真的羞涩的很,你的一个字一个字的看,一遍又一遍的看,一下是我的开发步骤:希望能对其他的人起到帮助作用:
·网页授权域名是为获取openid配置的:本文不过多说明openid获取方法
·支付授权目录配置,这个配置的目的为支付准备的因为微信要求支付的页面必须的在配置目录下
public class UnifiedOrder
{
///
/// 公共号ID(微信分配的公众账号 ID)
///
public string _appid = "";
public string appid
{
get { return _appid; }
set { _appid = value; }
}
///
/// 商户号(微信支付分配的商户号)
///
public string _mch_id = "";
public string mch_id
{
get { return _mch_id; }
set { _mch_id = value; }
}
///
/// 微信支付分配的终端设备号
///
public string _device_info = "";
public string device_info
{
get { return _device_info; }
set { _device_info = value; }
}
///
/// 随机字符串,不长于 32 位
///
public string _nonce_str = "";
public string nonce_str
{
get { return _nonce_str; }
set { _nonce_str = value; }
}
///
/// 签名
///
public string _sign = "";
public string sign
{
get { return _sign; }
set { _sign = value; }
}
///
/// 商品描述
///
public string _body = "";
public string body
{
get { return _body; }
set { _body = value; }
}
///
/// 附加数据,原样返回
///
public string _attach = "";
public string attach
{
get { return _attach; }
set { _attach = value; }
}
///
/// 商户系统内部的订单号,32个字符内、可包含字母,确保在商户系统唯一,详细说明
///
public string _out_trade_no = "";
public string out_trade_no
{
get { return _out_trade_no; }
set { _out_trade_no = value; }
}
///
/// 订单总金额,单位为分,不能带小数点
///
public int _total_fee = 0;
public int total_fee
{
get { return _total_fee; }
set { _total_fee = value; }
}
///
/// 终端IP
///
public string _spbill_create_ip = "";
public string spbill_create_ip
{
get { return _spbill_create_ip; }
set { _spbill_create_ip = value; }
}
///
/// 订 单 生 成 时 间 , 格 式 为yyyyMMddHHmmss,如 2009 年12 月 25 日 9 点 10 分 10 秒表示为 20091225091010。时区为 GMT+8 beijing。该时间取自商户服务器
///
public string _time_start = "";
public string time_start
{
get { return _time_start; }
set { _time_start = value; }
}
///
/// 交易结束时间
///
public string _time_expire = "";
public string time_expire
{
get { return _time_expire; }
set { _time_expire = value; }
}
///
/// 商品标记 商品标记,该字段不能随便填,不使用请填空,使用说明详见第 5 节
///
public string _goods_tag = "";
public string goods_tag
{
get { return _goods_tag; }
set { _goods_tag = value; }
}
///
/// 接收微信支付成功通知
///
public string _notify_url = "";
public string notify_url
{
get { return _notify_url; }
set { _notify_url = value; }
}
///
/// JSAPI、NATIVE、APP
///
public string _trade_type = "";
public string trade_type
{
get { return _trade_type; }
set { _trade_type = value; }
}
///
/// 用户标识 trade_type 为 JSAPI时,此参数必传
///
public string _openid = "";
public string openid
{
get { return _openid; }
set { _openid = value; }
}
///
/// 只在 trade_type 为 NATIVE时需要填写。
///
public string _product_id = "";
public string product_id
{
get { return _product_id; }
set { _product_id = value; }
}
public string _sign_type = "";
public string sign_type
{
get { return _sign_type; }
set { _sign_type = value; }
}
}
实现的方法:
//创建随机字符串32位
public static string CreateNonce()
{
char[] constant = new char[]
{
'0','1','2','3','4','5','6','7','8','9',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
};
StringBuilder newRandom = new StringBuilder(constant.Length);
Random rd = new Random(Guid.NewGuid().GetHashCode());
for (int i = 0; i < 32; i++)
{
newRandom.Append(constant[rd.Next(constant.Length)]);
}
return newRandom.ToString();
}
//创建签名
public static string CreateSign(Dictionary data, string key)
{
SortedDictionary data1 = new SortedDictionary();
foreach (KeyValuePair item in data)
{
data1.Add(item.Key, item.Value);
}
string s = string.Empty;
foreach (KeyValuePair item in data1)
{
s += item.Key + "=" + item.Value + "&"; //HttpUtility.UrlEncode(item.Value, Encoding.UTF8)
}
s += "key=" + key;
return MD5(s).ToUpper();
}
//md5加密
public static string MD5(string data)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
bytes = md5.ComputeHash(bytes);
md5.Clear();
string s = string.Empty;
for (int i = 0; i < bytes.Length; i++)
{
s += Convert.ToString(bytes[i], 16).PadLeft(2, '0');
}
return s.PadLeft(32, '0');
}
//统一下单prepay_id
public static string getPrepay_id( Model.UnifiedOrder order, string key)
{
string return_string = string.Empty;
Dictionary sParams = new Dictionary();
sParams.Add("appid", order.appid);
sParams.Add("attach", order.attach);
sParams.Add("body", order.body);
sParams.Add("device_info", order.device_info);
sParams.Add("mch_id", order.mch_id);
sParams.Add("nonce_str", order.nonce_str);
sParams.Add("notify_url", order.notify_url);
sParams.Add("openid", order.openid);
sParams.Add("out_trade_no", order.out_trade_no);
sParams.Add("spbill_create_ip", order.spbill_create_ip);
sParams.Add("total_fee", order.total_fee.ToString());
sParams.Add("trade_type", order.trade_type);
sParams.Add("sign_type", order.sign_type);
// order.sign = getsign(sParams, key);
order.sign = CreateSign(sParams, key);
sParams.Add("sign", order.sign);
//拼接成XML请求数据
StringBuilder sbPay = new StringBuilder();
foreach (KeyValuePair k in sParams)
{
if (k.Key == "attach" || k.Key == "body" || k.Key == "sign")
{
sbPay.Append("<" + k.Key + ">" + k.Key + ">");
}
else
{
sbPay.Append("<" + k.Key + ">" + k.Value + "" + k.Key + ">");
}
}
return_string = string.Format("{0} ", sbPay.ToString());
byte[] byteArray = Encoding.UTF8.GetBytes(return_string);
return_string = Encoding.GetEncoding("UTF-8").GetString(byteArray);
return return_string;
}
js通过调用此方法获得prepay_id
private string h5zhifu(HttpContext context)
{
Model.UnifiedOrder ufo = new Model.UnifiedOrder();
ufo.openid = "oEfd2wTE4TLaYYDGHzJH7jy1GM5w";
ufo.appid = WeiXinUtil.AppID;
ufo.attach = "qin"; //附加数据
ufo.body = "test"; //商品描述
ufo.device_info = "qqq";
ufo.mch_id = "1460089802"; //商户号
ufo.nonce_str = WeiXinUtil.CreateNonce(); //随机字符串
ufo.notify_url = "http://www.yuyue58.cn"; //通知地址
ufo.out_trade_no = WeiXinUtil.GetTimeStamp() + "001"; //商户内部订单号
// ufo.spbill_create_ip = WeiXinUtil.getIP();
ufo.spbill_create_ip = "180.173.29.203";
ufo.total_fee = 1; //支付金额
ufo.trade_type = "JSAPI"; //交易类型
ufo.sign_type = "MD5"; //签名类型
String preid = WeiXinUtil.getPrepay_id(ufo, WeiXinUtil.Key);
string url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //微信支付接口
String getid =WeiXinUtil.PostXmlToUrl(url,preid);
return getid;
}
js通过此方法获得签名paySign
特别注意这里的paySign是有appId,timeStamp,nonceStr,package,signType这5个请求参数生成的
//获取微信签名
private string getPaysign(HttpContext context) {
string timestamp = context.Request.Params["timestamp"];
string suiNum = context.Request.Params["suiNum"];
string prepay_ids = context.Request.Params["prepay_id"];
Dictionary sParams = new Dictionary();
sParams.Add("appId","wxf96f8d284bc577f7");
sParams.Add("timeStamp",timestamp);
sParams.Add("nonceStr",suiNum);
sParams.Add("package", "prepay_id=" + prepay_ids);
sParams.Add("signType", "MD5");
string paysign = WeiXinUtil.CreateSign(sParams, WeiXinUtil.Key);
return paysign;
}
$(function (){
$(".btn").click(function () {
//预支付交易会话标识
prepay_id = $.ajax({
url: '../Ajax.ashx',
type: 'POST',
data: { action: "h5zhifu", },
dataType: 'XML',
async: false
}).responseText;
var a = $.parseXML(prepay_id);
prepay_ids = $(a).find('prepay_id').text(); //获取prepay_id
//获取时间戳和随机字符串
str = $.ajax({
url: '../Ajax.ashx',
type: 'POST',
data: { action: "getTimeStampAndSuiNum", },
dataType: 'html',
async: false
}).responseText;
arr2 = String(str).split("|");
timestamp = arr2[0];
suiNum = arr2[1];
//获取微信签名
paysign = $.ajax({
url: '../Ajax.ashx',
type: 'POST',
data: { action: "getPaysign", timestamp: timestamp, suiNum: suiNum, prepay_id: prepay_ids },
dataType: 'html',
async: false
}).responseText;
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": "wxf96f8d284bc577f7", //公众号名称,由商户传入
"timeStamp": timestamp, //时间戳,自1970年以来的秒数
"nonceStr": suiNum, //随机串
"package":"prepay_id=" + prepay_ids,
"signType": "MD5", //微信签名方式:
"paySign": paysign //微信签名
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
window.location = "success.aspx";
}
// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回 ok,但并不保证它绝对可靠。
}
)
});
源码中的代码是公司的项目,所以删出来部分内容,仅仅留下了与支付有关的代码,仅供参考,写的可能不够好希望谅解。
源码链接