.Net微信服务商平台ApiV3接口
最近做个对接微信服务商平台的小程序项目,大概要实现的流程是:a)特约商户进件 > b)生成带参数的小程序码 > c)小程序支付 > d)分账,记录一下,希望能对需要的朋友有所帮助
开始
在开始之前建议仔细读微信官方文档,接口规则及api文档
https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay-1.shtml
https://pay.weixin.qq.com/wiki/doc/apiv3_partner/index.shtml
目录
整个流程开发步骤如下:
一、(签名)
二、(获取证书、敏感信息加密)
三、(上传图片)
四、(特约商户进件)
五、(生成小程序码)
六、(微信小程序支付)
七、(分账)
正文
在开始之前请确保你已经获取商户号、证书、秘钥、小程序appid、appsecret
一、签名
文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay4_0.shtml
1、生成签名
/// <param name="url">微信的接口地址</param>
/// <param name="method">请求的方式GET,POST,PUT</param>
/// <param name="jsonParame">post请求的数据,json格式 ,get时传空</param>
/// <param name="privateKey">apiclient_key.pem中的内容,不要-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----</param>
/// <param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param>
/// <param name="serialNo">商户证书号</param>
/// <returns></returns>
protected string GetAuthorization(string url, string method, string jsonParame, string privateKey, string merchantId, string serialNo)
{
var uri = new Uri(url);
string urlPath = uri.PathAndQuery;
string nonce = Guid.NewGuid().ToString();
var timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
//数据签名 HTTP请求方法\n接口地址的url\n请求时间戳\n请求随机串\n请求报文主体\n
method = string.IsNullOrEmpty(method) ? "" : method;
string message = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n", method, urlPath, timestamp, nonce, jsonParame);
string signTxt = Sign(message, privateKey); //Authorization和格式
string authorzationTxt = string.Format("WECHATPAY2-SHA256-RSA2048 mchid=\"{0}\",nonce_str=\"{1}\",timestamp=\"{2}\",serial_no=\"{3}\",signature=\"{4}\"",
merchantId,
nonce,
timestamp,
serialNo,
signTxt
);
return authorzationTxt;
} protected string Sign(string message, string privateKey)
{
byte[] keyData = Convert.FromBase64String(privateKey);
using (CngKey cngKey = CngKey.Import(keyData, CngKeyBlobFormat.Pkcs8PrivateBlob))
using (RSACng rsa = new RSACng(cngKey))
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
return Convert.ToBase64String(rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
}
}
2、放到请求头
string Authorization = GetAuthorization(url, method, postData, privateKey, merchantId, serialNo);
request.Headers.Add("Authorization", Authorization);
3、完整的请求方法
/// <param name="url">微信的接口地址</param>
/// <param name="postData">post请求的数据,json格式 </param>
/// <param name="privateKey">apiclient_key.pem中的内容,不要-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----</param>
/// <param name="merchantId">发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid</param>
/// <param name="serialNo">商户证书号</param>
/// <returns></returns>
public string postJson(string url, string postData, string privateKey, string merchantId, string serialNo, string method = "POST")
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = method;
request.ContentType = "application/json;charset=UTF-8";
request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36";
request.Accept = "application/json"; string Authorization = GetAuthorization(url, method, postData, privateKey, merchantId, serialNo);
request.Headers.Add("Authorization", Authorization);
if (!string.IsNullOrEmpty(postData))
{
byte[] paramJsonBytes;
paramJsonBytes = System.Text.Encoding.UTF8.GetBytes(postData);
request.ContentLength = paramJsonBytes.Length;
Stream writer;
try
{
writer = request.GetRequestStream();
}
catch (Exception)
{
writer = null;
Console.Write("连接服务器失败!");
}
writer.Write(paramJsonBytes, 0, paramJsonBytes.Length);
writer.Close();
} HttpWebResponse response;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
response = ex.Response as HttpWebResponse;
}
Stream resStream = response.GetResponseStream();
StreamReader reader = new StreamReader(resStream);
string text = reader.ReadToEnd();
return text;
}
二、获取证书、敏感信息加密
调用特约商户进件接口之前需要做三个工作:获取证书、敏感信息加密、上传图片
获取证书的目的是敏感信息加密需要用证书里解密得到的pubkey,然后用pubkey去对敏感信息进行加密
1、获取证书
获取证书接口比较简单,直接调用上边的请求方法
public static certModel GetCert()
{
string url = "https://api.mch.weixin.qq.com/v3/certificates";
string merchantId = WxPayConfig.MCHID; //商户号
string serialNo = WxPayConfig.SERIAL_NO; //证书编号
string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY----- string transactionsResponse = postJson(url, string.Empty, privateKey, merchantId, serialNo,"GET");
var result = JsonConvert.DeserializeObject<certModel>(transactionsResponse);
return result;
}
GetCert()
用到的model
public class certModel
{
public List<Data> data { get; set; }
} public class Data
{
public string serial_no { get; set; }
public string effective_time { get; set; }
public string expire_time { get; set; }
public Encrypt_certificate encrypt_certificate { get; set; } }
public class Encrypt_certificate
{
public string algorithm { get; set; }
public string nonce { get; set; }
public string associated_data { get; set; }
public string ciphertext { get; set; }
}
certModel
调用成功直接返回证书list,我们需要用v3秘钥解密得到公钥
var cmodel = GetCert().data.OrderByDescending(t => t.expire_time).FirstOrDefault();
string pubkey = AesGcmHelper.AesGcmDecrypt(cmodel.encrypt_certificate.associated_data, cmodel.encrypt_certificate.nonce, cmodel.encrypt_certificate.ciphertext);
pubkey = pubkey.Replace("-----BEGIN CERTIFICATE-----", "").Replace("-----END CERTIFICATE-----", ""); //解密方法
public class AesGcmHelper
{
private static string ALGORITHM = "AES/GCM/NoPadding";
private static int TAG_LENGTH_BIT = 128;
private static int NONCE_LENGTH_BYTE = 12;
private static string AES_KEY = WxPayConfig.V3KEY;//你的v3秘钥 public static string AesGcmDecrypt(string associatedData, string nonce, string ciphertext)
{
GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
AeadParameters aeadParameters = new AeadParameters(
new KeyParameter(Encoding.UTF8.GetBytes(AES_KEY)),
128,
Encoding.UTF8.GetBytes(nonce),
Encoding.UTF8.GetBytes(associatedData));
gcmBlockCipher.Init(false, aeadParameters); byte[] data = Convert.FromBase64String(ciphertext);
byte[] plaintext = new byte[gcmBlockCipher.GetOutputSize(data.Length)];
int length = gcmBlockCipher.ProcessBytes(data, 0, data.Length, plaintext, 0);
gcmBlockCipher.DoFinal(plaintext, length);
return Encoding.UTF8.GetString(plaintext);
}
}
pubkey
2、敏感信息加密
我们上一步得到了pubkey,然后对一些敏感信息字段(如用户的住址、银行卡号、手机号码等)进行加密
//text 为要加密的字段值
RSAEncrypt(text, UTF8Encoding.UTF8.GetBytes(pubkey)); public static string RSAEncrypt(string text, byte[] publicKey)
{
using (var x509 = new X509Certificate2(publicKey))
{
using (var rsa = (RSACryptoServiceProvider)x509.PublicKey.Key)
{
var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1); return Convert.ToBase64String(buff);
}
}
}
RSAEncrypt
这一步需要注意
//使用OaepSHA1
var buff = rsa.Encrypt(Encoding.UTF8.GetBytes(text), RSAEncryptionPadding.OaepSHA1);
三、上传图片
特约商户进件需要上传身份证、营业执照、银行卡等,这就需要通过图片上传API预先生成MediaID
先看接口文档https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter2_1_1.shtml
我封装了一个方法,直接上代码
public string UploadImg(string imgPath)
{
string filePath = HttpContext.Current.Server.MapPath(imgPath);
var filename = Path.GetFileName(filePath);
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
Byte[] imgBytesIn = new Byte[fs.Length];
fs.Read(imgBytesIn, 0, imgBytesIn.Length);
fs.Close(); byte[] hash = SHA256Managed.Create().ComputeHash(imgBytesIn); StringBuilder builder = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
builder.Append(hash[i].ToString("x2"));
}
var sha256 = builder.ToString();
string metaStr = "{\"filename\":\""+ filename + "\",\"sha256\":\"" + sha256 + "\"}";
string media_id = UploadImgApi(metaStr, imgBytesIn, filename);
return media_id;
} public static string UploadImgApi(string metaStr, Byte[] imgBytesIn,string filename)
{
string url = "https://api.mch.weixin.qq.com/v3/merchant/media/upload"; string merchantId = WxPayConfig.MCHID; //商户号
string serialNo = WxPayConfig.SERIAL_NO; //证书编号
string privateKey = WxPayConfig.PRIVATEKEY;
#region 定义请求体中的内容 并转成二进制 string boundary = "lc199aecd61b4653ef";
string Enter = "\r\n";
string campaignIDStr1
= "--" + boundary
+ Enter
+ "Content-Disposition: form-data; name=\"meta\";"
+ Enter
+ "Content-Type:application/json;"
+ Enter
+ Enter
+ metaStr
+ Enter
+ "--" + boundary
+ Enter
+ "Content-Disposition:form-data;name=\"file\";filename=\""+ filename + "\";"
+ Enter
+ "Content-Type:image/jpeg"
+ Enter
+ Enter;
byte[] byteData2
= imgBytesIn;
string campaignIDStr3
= Enter
+ "--" + boundary
+ Enter;
var byteData1 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr1); var byteData3 = System.Text.Encoding.UTF8.GetBytes(campaignIDStr3);
#endregion string transactionsResponse = UploadImg_postJson(url, byteData1, byteData2, byteData3, metaStr, privateKey, merchantId, serialNo, boundary, "POST");
var result=JsonConvert.DeserializeObject<uploadModel>(transactionsResponse);
Thread.Sleep(500);
return result.media_id;
} public class uploadModel
{
public string media_id { get; set; }
}
UploadImg
上传图片api需要注意请求主体类型、参与签名的字符串及body格式
我又单独写了个请求方法
public string UploadImg_postJson(string url, byte[] b1, byte[] b2, byte[] b3, string metaStr, string privateKey, string merchantId, string serialNo, string boundary, string method = "POST")
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = method;
//request.ContentType = "application/json;charset=UTF-8";
request.ContentType = "multipart/form-data;boundary=" + boundary;
request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3100.0 Safari/537.36";
request.Accept = "application/json";
string Authorization = GetAuthorization(url, method, metaStr, privateKey, merchantId, serialNo);
request.Headers.Add("Authorization", Authorization); Stream writer;
try
{
writer = request.GetRequestStream();
}
catch (Exception)
{
writer = null;
}
writer.Write(b1, 0, b1.Length);
writer.Write(b2, 0, b2.Length);
writer.Write(b3, 0, b3.Length);
writer.Close(); HttpWebResponse response;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
response = ex.Response as HttpWebResponse;
}
Stream resStream = response.GetResponseStream();
StreamReader reader = new StreamReader(resStream);
string text = reader.ReadToEnd();
return text;
}
UploadImg_postJson
最终返回media_id,存入合适的位置,方便使用
{
"media_id": "H1ihR9JUtVj-J7CJqBUY5ZOrG_Je75H-rKhTG7FUmg9sxNTbRN54dFiUHnhg
rBQ6EKeHoGcHTJMHn5TAuLVjHUQDBInSWXcIHYXOeRa2OHA"
}
四、特约商户进件
上边步骤通了之后,到这就很简单了,这一步的主要难点是请求参数太多了,很容易出错
注意:
• 商户上送敏感信息时使用微信支付平台公钥加密,证书序列号包含在请求HTTP头部的Wechatpay-Seria
需要在请求接口helder里加入Wechatpay-Seria
request.Headers.Add("Wechatpay-Serial", serial_no);
另外一点注意的这里的serial_no是GetCert()接口里获取到的serial_no
调用成功返回微信支付申请单号
{
"applyment_id": 2000002124775691
}
这一步完成之后可以拿到applyment_id请求查询申请单接口获取结果
成功返回sign_url签约连接发给特约商户相应负责人完成签约,即结束商户进件流程
五、生成带参数的小程序码
特约商户签约完成之后,服务商平台便可以代商户发起收款,此时我们需要分别给不同的商户生成不同的收款码,其实只需要传入商家的id即可区别处理
//storeid是商家唯一Id
public static string CreateQR(string storeid)
{
{
var page = "pages/custom/index";//扫码打开页面
var scene = storeid;//参数
//获取小程序的appid和secret
var appId = WxPayConfig.XCXAPPID;
var secret = WxPayConfig.XCXKEY;
string result = HttpGet($"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appId}&secret={secret}"); tokenModel rb = JsonConvert.DeserializeObject<tokenModel>(result); var url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + rb.access_token; var strUrl = url;
var request = (HttpWebRequest)WebRequest.Create(strUrl);
request.Method = "POST";
request.ContentType = "application/json;charset=UTF-8";
var data = new JsonData { ["page"] = page, ["scene"] = scene }; string jso = data.ToJson();
var payload = Encoding.UTF8.GetBytes(jso);
request.ContentLength = payload.Length;
var writer = request.GetRequestStream();
writer.Write(payload, 0, payload.Length);
writer.Close();
var response = (HttpWebResponse)request.GetResponse();
var s = response.GetResponseStream(); var qrCodeImgBase64 = StreamToBytes(s); //将流保存
string filename= storeid + ".png";
string returnpath= "/UpLoadFiles/StoreQR/" + filename;
string filepath = HttpContext.Current.Server.MapPath("/UpLoadFiles/StoreQR/") + filename;
System.IO.File.WriteAllBytes(filepath, qrCodeImgBase64);
return returnpath;
}
}
CreateQR
六、小程序支付JSAPI下单接口
有了商家码就能分别为商家发起支付申请,签约商户都有一个分配的商户号sub_mchid,注意请求参数里的商户号即这个,需要根据二维码的参数去获取
public static string V3Pay(string sub_mchid,string openid,int amount,string ordernumber,string description)
{
string url = "https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi"; string appid = WxPayConfig.XCXAPPID;
string merchantId = WxPayConfig.MCHID; //商户号
string serialNo = WxPayConfig.SERIAL_NO; //证书编号
string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY----- WxPayData postData = new WxPayData();
postData.SetValue("sp_appid", appid);
postData.SetValue("sp_mchid", merchantId);
postData.SetValue("sub_mchid", sub_mchid);
postData.SetValue("description", description);
postData.SetValue("out_trade_no", ordernumber);
postData.SetValue("notify_url", WxPayConfig.NOTIFY_URL);
WxPayData settle_info = new WxPayData();
settle_info.SetValue("profit_sharing",true);
postData.SetValue("settle_info", settle_info);
WxPayData _amount = new WxPayData();
_amount.SetValue("total", amount);
_amount.SetValue("currency", "CNY");
postData.SetValue("amount", _amount);
WxPayData payer = new WxPayData();
payer.SetValue("sp_openid", openid);
postData.SetValue("payer", payer); var postJson = postData.ToJsonFor();
string result = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
var result = JsonConvert.DeserializeObject<payModel>(result);
return result.prepay_id;
}
V3Pay
请求参数按照自己的方法去构建,json格式
通过JSAPI下单接口获取到发起支付的必要参数prepay_id,然后使用微信支付提供的小程序方法调起小程序支付
public static string GetJsApiParameters(string prepay_id)
{
string appid = WxPayConfig.XCXAPPID;
string privateKey = WxPayConfig.PRIVATEKEY;
string timestamp = WxPayApi.GenerateTimeStamp();
string nonceStr = WxPayApi.GenerateNonceStr();
string package = "prepay_id=" + prepay_id;
WxPayData jsApiParam = new WxPayData();
jsApiParam.SetValue("appId", appid);
jsApiParam.SetValue("timeStamp", timestamp);
jsApiParam.SetValue("nonceStr", nonceStr);
jsApiParam.SetValue("package", package);
jsApiParam.SetValue("signType", "RSA");
string message = string.Format("{0}\n{1}\n{2}\n{3}\n", appid, timestamp, nonceStr, package);
string signTxt = Sign(message, privateKey);
jsApiParam.SetValue("paySign", signTxt); string parameters = jsApiParam.ToJson();
return parameters;
}
GetJsApiParameters
返回给小程序调用wx.requestPayment(OBJECT)发起微信支付
注意回调URL:该链接是通过基础下单接口中的请求参数“notify_url”来设置的,要求必须为https地址。请确保回调URL是外部可正常访问的,且不能携带后缀参数,否则可能导致商户无法接收到微信的回调通知信息。回调URL示例: “https://pay.weixin.qq.com/wxpay/pay.action”
public class V3Notify
{ public callbackViewModel GetNotifyData()
{
//接收从微信后台POST过来的数据
System.IO.Stream s = System.Web.HttpContext.Current.Request.InputStream;
int count = 0;
byte[] buffer = new byte[1024];
StringBuilder builder = new StringBuilder();
while ((count = s.Read(buffer, 0, 1024)) > 0)
{
builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
s.Flush();
s.Close();
s.Dispose(); var ReadStr = builder.ToString(); notifyModel wxPayNotify = Newtonsoft.Json.JsonConvert.DeserializeObject<notifyModel>(ReadStr);
//开始解密
string WxPayResourceDecryptModel = AesGcmHelper.AesGcmDecrypt(wxPayNotify.resource.associated_data, wxPayNotify.resource.nonce, wxPayNotify.resource.ciphertext);
var decryptModel= Newtonsoft.Json.JsonConvert.DeserializeObject<WxPayResourceDecryptModel>(WxPayResourceDecryptModel); var viewModel = new callbackViewModel();
if (decryptModel != null)
{
//查询
var model = queryOrder(decryptModel.out_trade_no, decryptModel.sp_mchid, decryptModel.sub_mchid);//订单查询接口
viewModel.code = model.trade_state;
viewModel.message = model.trade_state_desc;
}
else
{
viewModel.code = "FAIL";
viewModel.message = "数据解密失败";
}
return viewModel;
}
}
V3Notify
整个下单没有牵涉到业务方面的代码,你可以把你的业务代码写在合适的位置处理
七、分账
在请求分账之前先在微信服务商后台邀约商户授权分账并指定分账比例(最大30%),并且发起支付申请时请求参数指定profit_sharing为true
1、首先添加分账接收方
接收方必须先调用接口添加才能在下一步请求分账时使用,注意不允许重复的openid
public static receiverModel AddReceivers(string sub_mchid,string type,string account,string relation_type)
{
string url = "https://api.mch.weixin.qq.com/v3/profitsharing/receivers/add"; string appid = WxPayConfig.XCXAPPID;
string merchantId = WxPayConfig.MCHID; //商户号
string serialNo = WxPayConfig.SERIAL_NO; //证书编号
string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY----- WxPayData postData = new WxPayData();
postData.SetValue("sub_mchid", sub_mchid);
postData.SetValue("appid", appid);
postData.SetValue("type", type);
postData.SetValue("account", account);
postData.SetValue("relation_type", relation_type);
string postJson = postData.ToJson(); string transactionsResponse = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
var result = JsonConvert.DeserializeObject<receiverModel>(transactionsResponse);
return result;
}
AddReceivers
2、请求分账
public static receiverModel PayReceivers(string sub_mchid, string transaction_id, string out_order_no,List<WxPayData> receivers)
{
string url = "https://api.mch.weixin.qq.com/v3/profitsharing/orders"; string appid = WxPayConfig.XCXAPPID;
string merchantId = WxPayConfig.MCHID; //商户号
string serialNo = WxPayConfig.SERIAL_NO; //证书编号
string privateKey = WxPayConfig.PRIVATEKEY; // NOTE: 私钥不包括私钥文件起始的-----BEGIN PRIVATE KEY----- 亦不包括结尾的-----END PRIVATE KEY----- WxPayData postData = new WxPayData();
postData.SetValue("sub_mchid", sub_mchid);
postData.SetValue("appid", appid);
postData.SetValue("transaction_id", transaction_id);
postData.SetValue("out_order_no", out_order_no);
postData.SetValue("unfreeze_unsplit", true);
postData.SetValue("receivers", receivers);
string postJson = postData.ToJsonFor();
LogHelper.WriteLogToFile("PayReceivers-postJson:" + postJson); string transactionsResponse = postJson(url, postJson, privateKey, merchantId, serialNo, "POST");
var result = JsonConvert.DeserializeObject<receiverModel>(transactionsResponse);
return result;
}
PayReceivers
用到的model
public class receiverModel
{
public string sub_mchid { get; set; }
public string type { get; set; }
public string account { get; set; }
public string name { get; set; }
public string relation_type { get; set; }
public string custom_relation { get; set; }
}
receiverModel
至此完整流程全部走完,总结下来技术难度并不大,就是步骤多,并且要把握好调用的时机,再一个就是请求参数多,容易出错,要耐心。
如有问题请在评论区留言或私信我
.Net微信服务商平台ApiV3接口的更多相关文章
- PHP玩转微信公众平台自定义接口
从微信公众平台开通自定义回复后,就一直在关注微信接口这一块,很想用自定义回复这块做个站长工具的查询,例如PR查询,备案查询等,输入网址信息,就能自动获取PR,获取备案信息,应该是一个不错的想法.不过以 ...
- 微信公众平台API接口
简介 微信公众平台消息接口为开发者提供了一种新的消息处理方式.微信公众平台消息接口为开发者提供与用户进行消息交互的能力.对于成功接入消息接口的微信公众账号,当用户发消息给公众号,微信公众平台服务器会使 ...
- 微信公众平台消息接口API指南
简介 微信公众平台消息接口为开发者提供了一种新的消息处理方式.微信公众平台消息接口为开发者提供与用户进行消息交互的能力.对于成功接入消息接口的微信公众账号,当用户发消息给公众号,微信公众平台服务器会使 ...
- 微信公众平台消息接口开发-封装weixin.class.php
原文:微信公众平台消息接口开发-封装weixin.class.php 一.封装weixin.class.php 由于微信公众平台的通信使用的是特定格式的XML数据,每次接受和回复都要去做一大堆的数据处 ...
- 微信公众平台消息接口PHP版开发教程
原文:微信公众平台消息接口PHP版开发教程 一.写好接口程序 在你的服务器上上传好一个接口程序文件,如http://www.yourdomain.com/weixin.php 内容如下: &l ...
- 微信公众平台开发接口PHP SDK
以前没接触过微信公众平台开发,前几天刚找到实习公司就要求我做一个微信公众平台的应用,于是乎开始学习微信公众平台开发接口的调用,看开发文档之后还是不知道从何入手,只好上网找入门资料,终于在方倍工作室找到 ...
- 微信公众平台消息接口PHP版
使用前提条件:拥有一个公网上的HTTP服务器主机空间,具有创建目录.上传文件等权限.推荐新浪的SAE.http://sae.sina.com.cn/ 首先请注册微信公众平台的账号,注册地址:http: ...
- 微信公众平台消息接口开发-封装weixin.class.php(转)
一.封装weixin.class.php 由于微信公众平台的通信使用的是特定格式的XML数据,每次接受和回复都要去做一大堆的数据处理. 我们就考虑在这个基础上做一次封装,weixin.class.ph ...
- 微信公众平台消息接口开发(26)从Hello2BizUser文本到subscribe事件
微信公众平台 微信公众平台开发模式 消息接口 企业微信公众平台 Hello2BizUser subscribe 订阅事件 作者:方倍工作室 原文:http://www.cnblogs.com/txw1 ...
随机推荐
- vue element-ui .el-dialog 限制高度
<style scoped> /deep/ .el-dialog { height: 78vh; overflow: auto; } </style>
- 最长回文子序列---DP
问题描述 给定一个字符串s,找到其中最长的回文子序列.可以假设s的最大长度为1000. 解题思路 1.说明 首先要弄清楚回文子串和回文子序列的区别,如果一个字符串是"bbbab", ...
- Vue 2.0 与 Vue 3.0 响应式原理比较
Vue 2.0 的响应式是基于Object.defineProperty实现的 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 prop ...
- 「山东省队集训2021 Round 1」 半夜
考虑将 \(X\) 复制一次放到后面再对其长度为 \(n\) 的连续子串和 \(Y\) 求一波 \(\rm{Longest\ Common\ Subsequence}\) 就能得到 \(\Theta( ...
- Identity角色管理三(创建角色)
首先创建视图模型 using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace Shop.Vi ...
- Webpack:打包项目报错(eslint: debugger)
打包项目需要把项目中的debugger删除,否则会报错.
- vue+element+echarts柱状图+列表
前端由vue+element搭建框架,引入vue和element的index.js和css就可以写页面: 页面和js可以echarts官网实例看下都是有的,主要看下如何动态赋值: 柱状图和列表: &l ...
- 关于FeignClient上的RequestMapping不能生效的问题
问题 我有两个FeignClient共同继承了一个接口,两个Client有各自不同的url实现,其中一个需要加上类似于@RequestMapping作用在类上的效果,因为@RequestMapping ...
- java 笔记一些
面象对的umv 视图示例: 用户 银行 帐户 怎么关联 帐户代码: 文件命名 Account package com.atuigu.exer4; import org.omg.CORBA.PUB ...
- prometheus从零开始
本次的想法是做服务监控 并告警 主要线路如下图所示 1.运行prometheus docker方式 docker run -itd \ -p 9090:9090 \ -v /opt/prometh ...