上一节已经介绍了银联的公众号支付业务,以及如何注册成为开发者,这一节将创建一个控制台应用程序调启微信支付并成功付款。
一、请求协议
HTTP(S)
HTTP方法:GET
二、接口地址
测试环境:http://58.247.0.18:29015/v1/netpay/webpay/pay
生产环境:https://api-mop.chinaums.com/v1/netpay/webpay/pay
三、参数
3.1URL参数
参数名称 | 参数说明 | 参数类型 | 长度 | 是否必须 | 备注 |
authorization | 认证方式 | string | 是 | 值为OPEN-FORM-PARAM | |
appId | AppId | string | <=32 | 是 | |
timestamp | 时间戳 | string | 14 | 是 | yyyyMMddHHmmss |
nonce | 随机数 | string | <=128 | 是 | |
content | 业务内容 | string | 是 | ||
signature | 签名 | string | 是 | Base64_Encode(HmacSHA256 (appId + timestamp + nonce + SHA256_HEX(content), AppKey)) |
3.2业务内容主体(只列出必填与部分主要参数,详细参数请参考官方文档)
格式:JSON
参数名称 | 参数说明 | 参数类型 | 长度 | 是否必须 | 备注 |
msgId | 消息ID | string | <=64 | 否 | 原样返回 |
requestTimestamp | 报文请求时 间 | string | 是 | 格式yyyy-MM-dd HH:mm:ss | |
merOrderId | 商户订单号 | string | 是 | 商户自行生成(下面详细介绍) | |
mid | 商户号 | string | 15 | 是 | |
tid | 终端号 | string | 8 | 是 | |
instMid | 业务类型 | string | 是 | YUEDANDEFAULT | |
totalAmount | 支付总金额 | 1..100000000 | 是 | ||
notifyUrl | 支付结果通知地址 | string(url) | 否 | ||
returnUrl | 网页跳转地址 | string(url) | 否 |
四、参数准备
4.1appId、商户号、终端号、来源编码获取
注册成为开发者后可以获取到这几个参数,注册开发者请回顾上一节
4.2订单号规则与生成
以银商分配的4位来源编号作为账单号的前4位,且在商户系统中此账单号保证唯一。总长 度需大于6位,小于28位。银商的推荐规则为(无特殊情况下,建议遵守此规则):{来源编号(4位)}{时间(yyyyMMddmmHHssSSS)(17位)}{7位随机数}
public static string getMerOrderId(string number)//number即来源编号,一般为1017
{
string time = DateTime.Now.ToString("yyyyMMddHHmmssSSS");
System.Random Random = new System.Random();
int Result = Random.Next(1000000, 9999999);//7位随机数
return number += time += Result;
}
4.3 生成签名
Base64_Encode(HmacSHA256(appId + timestamp + nonce + SHA256_HEX(content), AppKey))
private static string createSignature(string appid, string timestamp, string nonce, string body, string appkey)
{
string signature = "";
SHA256 sha256 = new SHA256CryptoServiceProvider();
byte[] retVal = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(body));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
Console.WriteLine("SHA256:" + sb.ToString());
var encoding = new System.Text.UTF8Encoding();
byte[] keyByte = encoding.GetBytes(appkey);
byte[] messageBytes = encoding.GetBytes(appid + timestamp + nonce + sb.ToString());
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
signature = Convert.ToBase64String(hashmessage);
}
return signature;
}
4.4业务内容主体
业务主体格式为JSON字符串,示例代码为C#,我们通过引入Newtonsoft库来构建一个JSON对象,后面再转成字符串即可。
JObject jobject = new JObject();
jobject.Add("requestTimestamp", timestamp); // 报文请求时间
jobject.Add("merOrderId", merOrderId); // 商户订单号
jobject.Add("srcReserve", "qqyl"); // 请求系统预留字段
jobject.Add("mid", "898340149000005"); // 商户号
jobject.Add("tid", "88880001"); // 终端号
jobject.Add("instMid", "YUEDANDEFAULT"); // 业务类型
jobject.Add("attachedData", "fjsj"); //商户附加数据
jobject.Add("orderDesc", "zdms"); // 账单描述
jobject.Add("totalAmount", 1); // 支付总金额
jobject.Add("notifyUrl", "https://www.sina.com.cn"); // 支付结果通知地址
jobject.Add("returnUrl", "http://www.baidu.com"); // 网页跳转地址
string body = jobject.ToString();
一切准备就绪,下面是完整代码
/// <summary>
/// 前台支付
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
string payUrl = "http://58.247.0.18:29015/v1/netpay/webpay/pay";//测试地址
string appid = "10037e6f66f2d0f901672aa27d69XXXX";
string appkey = "47ace12ae3b348fe93ab46cee97cXXXX";
string timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
string merOrderId = getMerOrderId("1017");
string nonce = Guid.NewGuid().ToString().Replace("-","");
JObject jobject = new JObject();
jobject.Add("requestTimestamp", timestamp); // 报文请求时间
jobject.Add("merOrderId", merOrderId); // 商户订单号
jobject.Add("srcReserve", "qqyl"); // 请求系统预留字段
jobject.Add("mid", "898340149000005"); // 商户号
jobject.Add("tid", "88880001"); // 终端号
jobject.Add("instMid", "YUEDANDEFAULT"); // 业务类型
jobject.Add("attachedData", "fjsj"); //商户附加数据
jobject.Add("orderDesc", "zdms"); // 账单描述
jobject.Add("totalAmount", 1); // 支付总金额,单位:分,也就是支付0.01元
jobject.Add("notifyUrl", "https://www.sina.com.cn"); // 支付结果通知地址
jobject.Add("returnUrl", "http://www.baidu.com"); // 网页跳转地址
string body = jobject.ToString();
string signature = createSignature(appid, timestamp, nonce, body, appkey);
string connection = "Data Source=.;Initial Catalog=JwsoftBsFrame_20200606;Integrated Security=True;";
using (SqlConnection conn = new SqlConnection(connection))
{
conn.Open();
string sql = $"INSERT INTO A0_TestPay(requestTimestamp,appid,merOrderId ) VALUES ({timestamp},'{appid}',{merOrderId})";
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
cmd.ExecuteNonQuery();
}
}
//url即我们需要的最终结果,复制url到微信打开就能调起微信支付
string url = payUrl + "?authorization=OPEN-FORM-PARAM&appId=" + appid
+ "×tamp=" + timestamp
+ "&nonce=" + nonce
+ "&content=" + HttpUtility.UrlEncode(body, Encoding.UTF8) + "&signature=" + HttpUtility.UrlEncode(signature, Encoding.UTF8);
Console.WriteLine(url);
Console.ReadKey();
}
/// <summary>
/// 生成订单号
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public static string getMerOrderId(string number)
{
string time = DateTime.Now.ToString("yyyyMMddHHmmss");
System.Random Random = new System.Random();
int Result = Random.Next(1000000, 9999999);
return number += time += Result;
}
/// <summary>
/// 生成签名
/// </summary>
/// <param name="appid"></param>
/// <param name="timestamp"></param>
/// <param name="nonce"></param>
/// <param name="body"></param>
/// <param name="appkey"></param>
/// <returns></returns>
private static string createSignature(string appid, string timestamp, string nonce, string body, string appkey)
{
string signature = "";
//先计算出 body 的 sha256加密
SHA256 sha256 = new SHA256CryptoServiceProvider();
byte[] retVal = sha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(body));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
Console.WriteLine("SHA256:" + sb.ToString());
//在结合起来
var encoding = new System.Text.UTF8Encoding();
byte[] keyByte = encoding.GetBytes(appkey);
byte[] messageBytes = encoding.GetBytes(appid + timestamp + nonce + sb.ToString());
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
signature = Convert.ToBase64String(hashmessage);
}
return signature;
}
string url = payUrl + "?authorization=OPEN-FORM-PARAM&appId=" + appid
+ "×tamp=" + timestamp
+ "&nonce=" + nonce
+ "&content=" + HttpUtility.UrlEncode(body, Encoding.UTF8) + "&signature=" + HttpUtility.UrlEncode(signature, Encoding.UTF8);
示例:
url即我们需要的最终结果,复制url到微信打开就能调起微信支付。实际业务中,我们只需要构建好好这个url微信中跳转就好。
五、调起微信支付
- 将程序构建好的url复制到微信中打开,点击访问
- 成功调起微信支付后,就是熟悉的付款操作了
- jobject.Add("totalAmount", 1); // 支付总金额,单位:分,也就是支付0.01元
- jobject.Add("returnUrl", "http://www.baidu.com"); // 支付成功后网页跳转地址
- 如果检查程序没问题,但是点击链接,没有响应的话,可能是测试接口不稳定造成了,请在工作时间内进行测试调用。不是上班时间,估计银联那边把所有访问都拒绝了。
下一节,我们将继续讲解支付结果查询和退款查询的接口调用,我们测试支付的钱可以通过退款接口进行退回的。