billplz可以沙箱测试

发布时间:2026/7/10 20:57:32
billplz可以沙箱测试 请求https://www.billplz-sandbox.com/api/v3collection_id和apikey自己去https://main.billplz-sandbox.com/或https://sso.billplz-sandbox.com/网址用自己邮箱申请沙箱帐号来获取collection_id和apikey调用billplz账单public void ProcessRequest(HttpContext context) { if (context.Request.Cookies[wb163CmsUserFirst][UserID] null) { context.Response.Write({\status\:\2\,\url\:\用户未登录\}); return; } // 在文件顶部添加 using System.Net; ServicePointManager.Expect100Continue true; // 启用 TLS1.2和 TLS1.1 可选 ServicePointManager.SecurityProtocol (SecurityProtocolType)3072 | (SecurityProtocolType)768; // 仅测试环境可临时允许不验证证书生产环境不要启用 //ServicePointManager.ServerCertificateValidationCallback (sender, certificate, chain, sslPolicyErrors) true; try { decimal amount 0m; string _baseUrl https://www.billplz.com/api/v3; //string _baseUrl https://www.billplz-sandbox.com/api/v3; wb163Cms.Models.WebSet webset new wb163Cms.BLL.BLL_WebSet().loadConfig(System.Web.Hosting.HostingEnvironment.MapPath(ConfigurationManager.AppSettings[Configpath].ToString())); amount Convert.ToDecimal(context.Request.Params[amount].Trim()); string paytime context.Request.Params[paytime].Trim(); // Billplz amount is in cents (sen) — multiply by 100 int amountSen (int)Math.Round(amount * 100m); amountSen 100; var payload new { collection_id webset.billplzcollection_id, //collection_idwebset.billplzsandcollection_id, name wb163Cms.Common.DEncrypt.DEncrypt.Decrypt(context.Request.Cookies[wb163CmsUserFirst][UserID].ToString()), email 123gmail.com, amount amountSen, callback_url webset.WebUrlTools/BillplzHook.ashx,//支付成功回调函数 redirect_url webset.WebUrluser.html, description 11, reference_1 amountSen }; string url _baseUrl /bills; var req (HttpWebRequest)WebRequest.Create(url); req.Method POST; req.ContentType application/json; // Basic auth: username API key, password empty string auth Convert.ToBase64String(Encoding.UTF8.GetBytes(webset.billplzapikey :)); //string auth Convert.ToBase64String(Encoding.UTF8.GetBytes(webset.billplzsandapikey :)); req.Headers[Authorization] Basic auth; string json JsonConvert.SerializeObject(payload); byte[] data Encoding.UTF8.GetBytes(json); req.ContentLength data.Length; using (var s req.GetRequestStream()) { s.Write(data, 0, data.Length); } try { using (var resp (HttpWebResponse)req.GetResponse()) using (var sr new StreamReader(resp.GetResponseStream())) { string respText sr.ReadToEnd(); Bill bill JsonConvert.DeserializeObjectBill(respText); context.Response.Write({\status\:\1\,\url\:\bill.Url\}); return; } } catch (WebException wex) { using (var r wex.Response as HttpWebResponse) { if (r ! null) { using (var sr new StreamReader(r.GetResponseStream())) { string error sr.ReadToEnd(); throw new Exception(Billplz API error: error); } } throw; } } if (true) { context.Response.Write(1); return; } } catch (Exception ex) { context.Response.Write({\status\:\2\,\url\:\\}); return; } }回调函数BillplzHook.ashxpublic void ProcessRequest(HttpContext context) { context.Response.ContentType text/plain; string body; using (var reader new StreamReader(context.Request.InputStream)) { body reader.ReadToEnd(); } wb163Cms.Models.WebSet webset new wb163Cms.BLL.BLL_WebSet().loadConfig(System.Web.Hosting.HostingEnvironment.MapPath(ConfigurationManager.AppSettings[Configpath].ToString())); //string xSignatureKey webset.billplzsandXSignaturekey; string xSignatureKey webset.billplzXSignaturekey; try { var dict ParseQueryString(body); if (!dict.TryGetValue(x_signature, out string receivedSignature)) { context.Response.StatusCode 500; context.Response.Write(error); } bool isValid VerifySignature(dict, xSignatureKey, receivedSignature); string paid dict.TryGetValue(paid, out var paid1) ? paid1 : ;//支付成功状态 string amount dict.TryGetValue(amount, out var amount1) ? amount1 : ;//金额 string userid dict.TryGetValue(name, out var userid1) ? userid1 : ;//用户id decimal money Convert.ToDecimal(amount) / 100M;//马币单位是仙要除去100才能是1马币 money - 1M; BLL_User ubll new BLL_User(); wb163Cms.Models.User modeluser ubll.GetModel(int.Parse(userid)); if (paid trueisValid)//支付成功 { //充值直接审核 wb163Cms.BLL.BLL_MoneyPay bll new BLL.BLL_MoneyPay(); wb163Cms.Models.MoneyPay model new Models.MoneyPay(); model.UserName modeluser.UserName; model.UserID modeluser.Id; model.Pic ; model.User_note ; model.RefNo ; model.Payway 0; model.BankName 在线支付; model.Mongeytype 0; model.Entermoney money; model.Paytime DateTime.Now; model.Status 1; model.Addtime Convert.ToDateTime(DateTime.Now.ToString(yyyy-MM-dd HH:mm:ss)); model.Checktime Convert.ToDateTime(DateTime.Now.ToString(yyyy-MM-dd HH:mm:ss)); model.Oppter ; model.Oppter_note ; model bll.Add(model); //wb163Cms.BLL.BLL_User blluser new BLL.BLL_User(); //充值记录 wb163Cms.BLL.BLL_User_charge_record bllrecord new BLL.BLL_User_charge_record(); wb163Cms.Models.User_charge_record modelrecord new Models.User_charge_record(); modelrecord.Amount money; modelrecord.Balance modeluser.Point; modelrecord.Currency RM; modelrecord.Afterpay modelrecord.Balance modelrecord.Amount; modelrecord.Posttime Convert.ToDateTime(DateTime.Now.ToString(yyyy-MM-dd HH:mm:ss)); modelrecord.Type 1; modelrecord.Remark 提交充值审核通过; modelrecord.User_id model.UserID; bllrecord.Add(modelrecord); //更新余额 modeluser.Point model.Entermoney; ubll.Update(modeluser); //ubll.UpdateField(userid, pointpoint money );//更新余额 //context.Response.Redirect(/user.html); context.Response.StatusCode 200; context.Response.Write(ok); } else { wb163Cms.Common.FsLog.CreateLog(billplz 更新报错, true); context.Response.StatusCode 500; context.Response.Write(error); } } catch (Exception ex) { // 记录日志 wb163Cms.Common.FsLog.CreateLog(billplz webhook error: ex.Message, true); context.Response.StatusCode 500; context.Response.Write(error); } } //解析分隔的数据为Dictionary static Dictionarystring, string ParseQueryString(string qs) { var result new Dictionarystring, string(StringComparer.OrdinalIgnoreCase); if (string.IsNullOrEmpty(qs)) return result; // 如果传入的是完整 URL截取 ? 之后的查询部分 int q qs.IndexOf(?); if (q 0) qs qs.Substring(q 1); var parts qs.Split(new[] { }, StringSplitOptions.RemoveEmptyEntries); foreach (var part in parts) { int eq part.IndexOf(); string key, value; if (eq 0) { key part.Substring(0, eq); value part.Substring(eq 1); } else { key part; value string.Empty; } // 使用 WebUtility.UrlDecode 做解码处理 %xx 和 key WebUtility.UrlDecode(key ?? string.Empty); value WebUtility.UrlDecode(value ?? string.Empty); result[key] value; } return result; } //验签 public static bool VerifySignature(Dictionarystring, string parameters, string xSignatureKey, string receivedSignature) { if (parameters null || string.IsNullOrEmpty(xSignatureKey) || string.IsNullOrEmpty(receivedSignature)) return false; // 1. 按照键名 ASCII 升序排列并拼接成 key1value1key2value2 格式 var sortedParams parameters .Where(p !string.IsNullOrEmpty(p.Key) p.Key ! x_signature) // 确保排除 x_signature .OrderBy(p p.Keyp.Value, StringComparer.Ordinal); var sourceString new StringBuilder(); foreach (var param in sortedParams) { sourceString.Append(param.Key).Append(param.Value|); } sourceString.Remove(sourceString.Length - 1, 1); Common.FsLog.CreateLog(签名sourceString.ToString(), true); // 2. 使用 HMAC-SHA256 计算签名 var encoding new UTF8Encoding(); byte[] keyBytes encoding.GetBytes(xSignatureKey); byte[] messageBytes encoding.GetBytes(sourceString.ToString()); using (var hmac new HMACSHA256(keyBytes)) { byte[] hashBytes hmac.ComputeHash(messageBytes); string calculatedSignature BitConverter.ToString(hashBytes).Replace(-, ).ToLowerInvariant(); // 3. 比对计算出的签名与接收到的签名 return string.Equals(calculatedSignature, receivedSignature, StringComparison.OrdinalIgnoreCase); } }