ps:接着之前的完成了微信授权获取用户的基础信息外
微信支付也需要快速完成,支付的确很多坑,大多数是不认真阅读开发文档导致
stemp1 :发起预支付api
此处遇到的坑是,由于需求中的信息,例如公众号下对应一个商户号,但是需求文档中给的商户号是错误的,不是这个公众号对应下的商户号,
直接被返回 公众号与商户号不一致!!!,此时经历了寻找好几个部门的人,终于找到了对应的商户号!然而已经懵逼了好久….
#region 扫码进行打赏操作
///
/// HttpPost
/// api/Appraise/ScanToAward
/// 打赏
///
///
[HttpPost]
[ActionName("ScanToAward")]
public IHttpActionResult ScanToAward(ScanToAwardModel model)
{
string scan_notify_url = "你的回调地址";
try
{
if (model == null)
{
throw new CustomException("操作失败,无效参数");
}
if (string.IsNullOrEmpty(model.totle_fee))
{
throw new CustomException("操作失败,无效打赏金额");
}
//if (string.IsNullOrEmpty(model.UserId))
//{
// throw new CustomException("操作失败,无效顾客信息");
//}
string prepay_id = "";
int crid = model.CID.ToIntForPage();
int uid = model.UserId.ToIntForPage();
decimal totalfee = model.totle_fee.ToDecimal();
DateTime now = DateTime.Now;
//数据库操作,省略*******
weixin_payment payment = new weixin_payment
{
appid = "",
mchid = "",
CID = cid,
body = "扫码打赏",
Name = cr.Name,
itime = now,
openid = userUserID.openid,
out_trade_no = "wx" + DateTime.Now.ToString("yyyyMMddHHmmssfff"),
scene_info = "扫码打赏",
SName = SpName,
UserId = uid,
notify_url = scan_notify_url,
total_fee = totalfee,
};
dbo.weixin_payment.Add(payment);
int r = dbo.SaveChanges();
if (r > 0)
{
string temp = WechatService.WechatPrePayScan(payment.body, payment, "JSAPI", "127.0.0.1", out prepay_id);
return Json(Success(temp.Replace("\\", "")));
}
else
{
return Json(getException("打赏失败"));
}
}
catch (CustomException ce)
{
// 数据库操作
return Json(getException(ce.Message));
}
catch (Exception ex)
{
// 数据库操作
return Json(getException(ex));
}
}
#endregion
stemp2 预支付主要函数,主要是进行签名,参数一定到正确,如下:
///
/// 执行微信预支付
///
/// 产品描述
/// 订单编号
///
public static string WechatPrePayScan(string gooddesc, mf_weixin_payment pay, string tradetype, string userip, out string prepay_id, string type = "buyerorder")
{
memberEntities dbo = new memberEntities();
decimal Patment = 0;//支付金额
string appid = Appid;//微信公众号Appid
string mchid = much_id;//微信支付商户号
string UserOpenid = "";//用户openid,JSAPI微信支付要用
byte[] goodsdescByte = System.Text.Encoding.Default.GetBytes(gooddesc);
gooddesc = goodsdescByte.Length >= 30 ? System.Text.Encoding.Default.GetString(goodsdescByte, 0, 30) : gooddesc;
switch (type)
{
case "buyerorder":
//操作数据库***
Patment = pay.total_fee;
if (tradetype == "JSAPI")
{
//获取订单用户openid
UserOpenid = pay.openid;
}
break;
case "rechargeorder":
//操作数据库***
Patment = pay.total_fee;
break;
default:
throw new CustomException("传入类型出错。");
}
//Patment = 1;
//微信接口价格是按“分”来计算的,且不能有小数点
int payment = Convert.ToInt32(Patment * 100);
//随机字符串
string nonce_str = Md5Hash(RandomNumber(10, true)).ToUpper();
//微信支付的订单号
string WxPayOrderSN = pay.out_trade_no;
//签名
SortedDictionary<string, string> SignParamsObj = new SortedDictionary<string, string>();
SignParamsObj.Add("appid", appid);
SignParamsObj.Add("body", gooddesc);
SignParamsObj.Add("mch_id", mchid);
SignParamsObj.Add("nonce_str", nonce_str);
SignParamsObj.Add("notify_url", pay.notify_url);
SignParamsObj.Add("out_trade_no", pay.out_trade_no);
if (tradetype == "JSAPI")
{
if (string.IsNullOrEmpty(UserOpenid))
throw new CustomException("网页支付必须绑定微信。");
else SignParamsObj.Add("openid", pay.openid);
}
SignParamsObj.Add("spbill_create_ip", userip);
SignParamsObj.Add("total_fee", payment.ToString());
SignParamsObj.Add("trade_type", tradetype);
//签名 方法1
string stringA = wechatService.MakeSignStr(SignParamsObj);
string sign = MD5Encrypt32(stringA + "&key=" + Key);
//string stringA = "appid=" + appid + "&body="
// + gooddesc + "&mch_id=" + mchid + "&nonce_str="
// + nonce_str + "¬ify_url=http://package.mfsj.cn&out_trade_no="
// + ID + "&openid=" + UserOpenid + "&spbill_create_ip=8.8.8.8&total_fee="
// + payment + "&trade_type=JSAPI";
//传入数据为XML格式
string data = ""
+ "{7} "
+ "{6} "
+ "{0} "
+ "{1} "
+ "{2}"
+ "{3} "
+ "{4} "
+ "{9} "
+ "{5} "
+ "{8} ";
if (!string.IsNullOrEmpty(UserOpenid))
{
data += "" + UserOpenid + "";
}
data += "";
data = string.Format(
data,
nonce_str,
sign,
pay.notify_url,
WxPayOrderSN,
payment,
NOTIFY_URL,
mchid,
appid,
tradetype,
userip);
//执行请求
string result = MethodHelper.RequestUrlByPOST("https://api.mch.weixin.qq.com/pay/unifiedorder", data);
//将返回结果转换成json字符串输出
XmlDocument doc = new XmlDocument();
doc.LoadXml(result);
string jsonresult = JsonConvert.SerializeXmlNode(doc);
jsonresult = jsonresult.Replace("#", "");
jsonresult = jsonresult.Replace("cdata-section", "cdata");
if (tradetype == "JSAPI")
{
return JsonConvert.SerializeObject(GetWechatJSSDKPayMsg(jsonresult, out prepay_id));
}
else
{
return JsonConvert.SerializeObject(GetWechatJSSDKPayMsg(jsonresult, out prepay_id));
}
}
经常报签名错误的原因有一下几个:http://jingyan.baidu.com/article/59703552c3c9808fc1074072.html 百度说得很多了
但是我们真的遇到了
1 key真的不对!公众平台的密钥和商户号的密钥是不一样的!!!微信支付审核成功之后会收到一封邮件,邮件中有appid 商户号,商户后台登录上号和密码,登录到商户后台:账户设置-安全设置-切换到API安全,下载证书,下面有一个api密匙,进去填写一个字符串 ,保存,后续两次签名都是用的这个手动设置的key!!!后来重新生成一个了;
2 openid要正确
3 金额分要注意,单位是用分的
4 仔细阅读文档后,就很少出错了
以下解释发起微信支付成功后的数据,返回响应wx的json给前台
后台如下:
///
/// 获取微信JSSDK支付调起所需要的信息
///
///
public static WechatJSSDKPayMessageModel GetWechatJSSDKPayMsg(string prepayresult, out string prepay_id)
{
//返回结果对象
WechatJSSDKPayMessageModel Result = new WechatJSSDKPayMessageModel();
//支付签名排序字典
SortedDictionary<string, string> SignParams = new SortedDictionary<string, string>();
//分析微信预支付返回结果,并取出预支付Id
JObject PrepayObj = (JObject)JsonConvert.DeserializeObject(prepayresult);
if (PrepayObj == null || PrepayObj["xml"] == null || PrepayObj["xml"]["return_code"] == null || PrepayObj["xml"]["return_code"]["cdata"] == null || PrepayObj["xml"]["result_code"] == null || PrepayObj["xml"]["result_code"]["cdata"] == null || PrepayObj["xml"]["return_msg"] == null || PrepayObj["xml"]["return_msg"]["cdata"] == null)
{
//return.getException(prepayresult);
throw new CustomException("微信预支付信息有误。");
}
if (PrepayObj["xml"]["return_code"]["cdata"].ToString().ToUpper() != "SUCCESS" || PrepayObj["xml"]["result_code"]["cdata"].ToString().ToUpper() != "SUCCESS")
{
//JsonReturn.getException(prepayresult);
throw new CustomException("微信预支付有误。");
}
//时间戳
Result.timeStamp = CreatenTimestamp().ToString();
//随机字符串
Result.nonceStr = Md5Hash(RandomNumber(10, true)).ToUpper();
//package
Result.package = "prepay_id=" + PrepayObj["xml"]["prepay_id"]["cdata"].ToString();
Result.prepay_id = PrepayObj["xml"]["prepay_id"]["cdata"].ToString();
Result.appId = Appid;
//把微信支付签名所需要的参数放入字典
SignParams.Add("appId", Appid);
SignParams.Add("timeStamp", Result.timeStamp);
SignParams.Add("nonceStr", Result.nonceStr);
SignParams.Add("package", Result.package);
SignParams.Add("signType", "MD5");
//生成签名
string WxPaySign = wechatService.MakeSignStr(SignParams);
WxPaySign += "&key=" + Key;
Result.paysign = Md5Hash(WxPaySign).ToUpper();
prepay_id = Result.prepay_id;
return Result;
}
前台如下:
//angular 打赏控制器
.controller('rewardCtrl', function ($scope, Utils, $ionicPopup, $ionicLoading, $http) {
$scope.referenceInfo = JSON.parse(window.sessionStorage.getItem('comment'));
console.log($scope.referenceInfo);
//各个金额等级
$scope.rewardMoney = [{money: 1}, {money: 3}, {money: 5}, {money: 7}, {money: 10}, {money: 20}];
$scope.importMoney = {};//其他金额
var myPopup;
$scope.isOK = function (reward) {
var sendData = {
BookId: $scope.referenceInfo.BookId,
d_fromID: $scope.referenceInfo.UserId,
d_totle_fee: reward,
CounselorId: $scope.referenceInfo.CounselorID
};
console.log(sendData);
$http({method: 'POST', url: API_URL + 'Appraise/AddAppraiseAward', data: sendData}).then(function (res) {
var temp = JSON.parse(res.data.info);
//console.log(temp);
//微信窗口
wx.chooseWXPay({
timestamp: temp.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: temp.nonceStr, // 支付签名随机串,不长于 32 位
package: temp.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
signType: 'MD5', // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: temp.paysign, // 支付签名
success: function (res) {
// 支付成功后的回调函数
console.log(res)
}
});
});
};
//弹框其他金额打赏
$scope.inputMoney = function () {
myPopup = $ionicPopup.show({
templateUrl: 'templates/reference/reward-popup.html',
scope: $scope
})
};
//确定其他输入金额打赏
$scope.otherReward = function () {
//判断输入的金额是否符合
if ($scope.importMoney.value === undefined || $scope.importMoney.value === '' || $scope.importMoney.value === null) {
$ionicLoading.show({
template: '请输入数字',
duration: 1000
});
}
$scope.isOK($scope.importMoney.value);
myPopup.close()
};
//关闭其他金额打赏
$scope.closePopup = function () {
myPopup.close()
};
});
stemp3 回调
刚开始的时候回调地址需要在公众号那边直接填写的,不填写永远也收不到回调
#region 微信回调主控制器
///
/// HttpPost WechatResponseModel wechat
/// 微信回调主控制器 回调
///
///
/// api/WeChat/ResultNotifyController
[HttpPost]
[ActionName("ResultNotifyController")]
public IHttpActionResult ResultNotifyController()
{
//一开始的时候做一个监控,看看有没有成功回调
Log4NetInfo.LogInfo("微信支付回调进入页面");
string resultFromWx = getPostStr();
var res = XDocument.Parse(resultFromWx);
//通信成功
if (res.Element("xml").Element("return_code").Value == "SUCCESS")
{
if (res.Element("xml").Element("result_code").Value == "SUCCESS")
{
string ordecode = res.Element("xml").Element("out_trade_no").Value;
var appraise = dbo.mf_appraise.Where(c => c.OrderId == ordecode).FirstOrDefault();
try
{
//操作数据库;
dbo.Entry(appraise).State = System.Data.Entity.EntityState.Modified;
int r = dbo.SaveChanges();
}
catch (Exception ex)
{
//操作数据库;
int r = dbo.SaveChanges();
}
return Json(new { return_code = "SUCCESS", return_msg = "OK" });
}
else
{
//操作数据库;
dbo.Entry(appraise).State = System.Data.Entity.EntityState.Modified;
int r = dbo.SaveChanges();
}
}
else
{
//操作数据库;
int r = dbo.SaveChanges();
}
Log4NetInfo.LogInfo("微信支付回调退出页面");
return Json(new { return_code = "", return_msg = "" });
}
//获得Post过来的数据 这里接收采摘网友的源码,因为快速开发,只能用现成的了。而且这个获取字节流的形式,试过了一般的方法拿不到回调的数据
public string getPostStr()
{
Int32 intLen = Convert.ToInt32(HttpContext.Current.Request.InputStream.Length);
byte[] b = new byte[intLen];
HttpContext.Current.Request.InputStream.Read(b, 0, intLen);
return System.Text.Encoding.UTF8.GetString(b);
}
到这里,微信jsapi支付就基本上完成。扫码支付需要使用到证书,其应用场景更多,将在后面的文中补上