最近微信公众号商城需要增加支付宝支付,因为微信内部屏蔽了支付宝的请求,所以需要采用浏览器方式打开,如下所示:
大家想必都有这种困惑——拿到支付宝的接口代码后,尽管里面的程序有注释,接口代码包中也附有开发说明,但还是不知道该如何入手。这不难想象是什么原因,因为自己并不了解这个接口的工作原理是什么?请看这篇文章http://www.cnblogs.com/tangself/archive/2010/02/09/1666257.html,这边就不讲太多原理,主要分清楚用的哪个版本,新的支付宝接口已经没有MD5加密,因为不安全,只保留了RSA加密方式,该项目因为以前已经申请过,所以采用的是老版的接口。
具体步骤如下:
1.下好对应的支付宝官方API,找到对应的语言,我这边采用的是.net
2.将代码拷贝到自己的项目中,根据自己的项目分层对应代码放到对应的项目中
3.对于个性化的功能配置都配置的独立对应的XML文件中,如支付XML
4.修改AlipayConfig.cs文件

1 #region 2 3 using System; 4 using System.Xml; 5 6 #endregion 7 8 namespace Com.Alipay 9 { 10 /// <summary> 11 /// 类名:Config 12 /// 功能:基础配置类 13 /// 详细:设置帐户有关信息及返回路径 14 /// 版本:3.3 15 /// 日期:2012-07-05 16 /// 说明: 17 /// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 18 /// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。 19 /// 如何获取安全校验码和合作身份者ID 20 /// 1.用您的签约支付宝账号登录支付宝网站(www.alipay.com) 21 /// 2.点击“商家服务”(https://b.alipay.com/order/myOrder.htm) 22 /// 3.点击“查询合作者身份(PID)”、“查询安全校验码(Key)” 23 /// </summary> 24 public class Config 25 { 26 static Config() 27 { 28 XmlDocument xmlDoc = new XmlDocument(); 29 xmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "\config\configPay.xml"); 30 XmlNode xmlNode = xmlDoc.SelectSingleNode("Configs/AliPay"); 31 //↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 32 //合作身份者ID,以2088开头由16位纯数字组成的字符串 33 Partner = xmlNode?.SelectSingleNode("Partner")?.InnerText; 34 35 //收款支付宝账号 36 SellerEmail = xmlNode?.SelectSingleNode("Seller_email")?.InnerText; 37 38 //交易安全检验码,由数字和字母组成的32位字符串 39 //如果签名方式设置为“MD5”时,请设置该参数 40 Key = xmlNode?.SelectSingleNode("Key")?.InnerText; 41 42 //商户的私钥 43 //如果签名方式设置为“0001”时,请设置该参数 44 PrivateKey = xmlNode?.SelectSingleNode("Private_key")?.InnerText; 45 ; 46 47 //支付宝的公钥 48 //如果签名方式设置为“0001”时,请设置该参数 49 PublicKey = xmlNode?.SelectSingleNode("Public_key")?.InnerText; 50 ; 51 52 //↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 53 54 //字符编码格式 目前支持 utf-8 55 InputCharset = xmlNode?.SelectSingleNode("Input_charset")?.InnerText; 56 ; 57 58 //签名方式,选择项:0001(RSA)、MD5 59 SignType = xmlNode?.SelectSingleNode("Sign_type")?.InnerText; 60 ; 61 //无线的产品中,签名方式为rsa时,sign_type需赋值为0001而不是RSA 62 63 //支付宝网关地址 64 GatewayNew = xmlNode?.SelectSingleNode("GATEWAY_NEW")?.InnerText; 65 66 //服务器异步通知页面路径 67 NotifyUrl = xmlNode?.SelectSingleNode("notify_url")?.InnerText; 68 69 //页面跳转同步通知页面路径 70 CallBackUrl = xmlNode?.SelectSingleNode("call_back_url")?.InnerText; 71 72 //操作中断返回地址 73 MerchantUrl = xmlNode?.SelectSingleNode("merchant_url")?.InnerText; 74 75 //返回格式 76 Format = xmlNode?.SelectSingleNode("format")?.InnerText; 77 78 //返回版本 79 Version = xmlNode?.SelectSingleNode("v")?.InnerText; 80 } 81 82 #region 属性 83 84 /// <summary> 85 /// 获取或设置合作者身份ID 86 /// </summary> 87 public static string Partner { get; set; } 88 89 /// <summary> 90 /// 获取或设置收款支付宝账号 91 /// </summary> 92 public static string SellerEmail { get; set; } 93 94 /// <summary> 95 /// 获取或设交易安全校验码 96 /// </summary> 97 public static string Key { get; set; } 98 99 /// <summary> 100 /// 获取或设置商户的私钥 101 /// </summary> 102 public static string PrivateKey { get; set; } 103 104 /// <summary> 105 /// 获取或设置支付宝的公钥 106 /// </summary> 107 public static string PublicKey { get; set; } 108 109 /// <summary> 110 /// 获取字符编码格式 111 /// </summary> 112 public static string InputCharset { get; } 113 114 /// <summary> 115 /// 获取签名方式 116 /// </summary> 117 public static string SignType { get; } 118 119 /// <summary> 120 /// 支付宝网关地址 121 /// </summary> 122 public static string GatewayNew { get; } 123 124 /// <summary> 125 /// 服务器异步通知页面路径 126 /// </summary> 127 public static string NotifyUrl { get; } 128 129 /// <summary> 130 /// 页面跳转同步通知页面路径 131 /// </summary> 132 public static string CallBackUrl { get; } 133 134 /// <summary> 135 /// 操作中断返回地址 136 /// </summary> 137 public static string MerchantUrl { get; } 138 139 /// <summary> 140 /// 返回格式 141 /// </summary> 142 public static string Format { get; } 143 144 /// <summary> 145 /// 返回版本 146 /// </summary> 147 public static string Version { get; } 148 149 #endregion 150 } 151 }
5.因为微信商城是由第三方用JAVA开发,我们采用接口的方式提供给他们,所以生成表单返回给对方,对方直接输出到浏览器跳到支付宝页面

1 #region 手机网站支付(支付宝支付) 2 3 /// <summary> 4 /// 提交支付 5 /// </summary> 6 /// <param name="orderId">订单号</param> 7 /// <returns></returns> 8 /// <remarks></remarks> 9 [WebMethod] 10 public ReturnEntity<string> SubmitAliPay(string orderId) 11 { 12 if (string.IsNullOrEmpty(orderId)) 13 { 14 return new ReturnEntity<string>(false, "订单编号不能为空"); 15 } 16 try 17 { 18 string posthtml = PayBLL.SubmitAliPay(orderId); 19 return new ReturnEntity<string>(!string.IsNullOrEmpty(posthtml), string.Empty, posthtml); 20 } 21 catch (Exception ex) 22 { 23 return new ReturnEntity<string>(false, ex.Message); 24 } 25 } 26 27 #endregion
具体生成表单方法放到业务逻辑层,方法如下

1 #region 手机网站支付(支付宝支付) 2 3 /// <summary> 4 /// 提交支付 5 /// </summary> 6 /// <param name="orderId">订单号</param> 7 /// <returns></returns> 8 /// <remarks></remarks> 9 public static string SubmitAliPay(string orderId) 10 { 11 //请求号 12 string req_id = DateTime.Now.ToString("yyyyMMddHHmmss") + new Random().Next(10000, 99999); 13 //必填,须保证每次请求都是唯一 14 15 //商户订单号 16 string out_trade_no = orderId; 17 //商户网站订单系统中唯一订单号,必填 18 19 //订单名称 20 string subject = orderId.StartsWith("R") ? "会员账户充值" : "会员在线购物"; 21 //必填 22 23 //付款金额 24 string total_fee = OrderBLL.GetOrderTotalFee(orderId); 25 if (string.IsNullOrEmpty(total_fee)) 26 { 27 throw new Exception("会员在线购物总额为0"); 28 } 29 if (Utils.ConvertRowData<double>(total_fee) == 0.00) 30 { 31 throw new Exception("会员在线购物总额为0"); 32 } 33 34 //必填 35 36 //请求业务参数详细 37 string req_dataToken = "<direct_trade_create_req>" + 38 "<notify_url>" + Config.NotifyUrl + "</notify_url>" + 39 "<call_back_url>" + Config.CallBackUrl + "</call_back_url>" + 40 "<seller_account_name>" + Config.SellerEmail + "</seller_account_name>" + 41 "<out_trade_no>" + out_trade_no + "</out_trade_no>" + 42 "<subject>" + subject + "</subject>" + 43 "<total_fee>" + total_fee + "</total_fee>" + 44 "<merchant_url>" + Config.MerchantUrl + "</merchant_url>" + 45 "</direct_trade_create_req>"; 46 //必填 47 48 //把请求参数打包成数组 49 Dictionary<string, string> sParaTempToken = new Dictionary<string, string> 50 { 51 {"partner", Config.Partner}, 52 {"_input_charset", Config.InputCharset.ToLower()}, 53 {"sec_id", Config.SignType.ToUpper()}, 54 {"service", "alipay.wap.trade.create.direct"}, 55 {"format", Config.Format}, 56 {"v", Config.Version}, 57 {"req_id", req_id}, 58 {"req_data", req_dataToken} 59 }; 60 61 //建立请求 62 string sHtmlTextToken = Submit.BuildRequest(Config.GatewayNew, sParaTempToken); 63 //URLDECODE返回的信息 64 Encoding code = Encoding.GetEncoding(Config.InputCharset); 65 sHtmlTextToken = HttpUtility.UrlDecode(sHtmlTextToken, code); 66 67 //解析远程模拟提交后返回的信息 68 Dictionary<string, string> dicHtmlTextToken = Submit.ParseResponse(sHtmlTextToken); 69 70 //获取token 71 string request_token = dicHtmlTextToken["request_token"]; 72 73 ////////////////////////////////////////////根据授权码token调用交易接口alipay.wap.auth.authAndExecute//////////////////////////////////////////// 74 75 76 //业务详细 77 string req_data = "<auth_and_execute_req><request_token>" + request_token + 78 "</request_token></auth_and_execute_req>"; 79 //必填 80 81 //把请求参数打包成数组 82 Dictionary<string, string> sParaTemp = new Dictionary<string, string> 83 { 84 {"partner", Config.Partner}, 85 {"_input_charset", Config.InputCharset.ToLower()}, 86 {"sec_id", Config.SignType.ToUpper()}, 87 {"service", "alipay.wap.auth.authAndExecute"}, 88 {"format", Config.Format}, 89 {"v", Config.Version}, 90 {"req_data", req_data} 91 }; 92 93 //建立请求 94 string sHtmlText = Submit.BuildRequest(Config.GatewayNew, sParaTemp, "get", "确认"); 95 return sHtmlText; 96 } 97 98 #endregion
6.接下来对方直接输出到浏览器如果参数,签名之类没有问题,则会跳到这个页面
接下来就是支付宝的事情了
7.支付宝支付后会有异步通知和返回两个操作,通常来说异步通知的优先级会大于同步返回,且功能准确性高
a.异步通知代码如下,主要状态码官网有说明,根据自己业务需要在对应分支下更新自己的业务逻辑,获取数据采用POST方式,返回的是XML数据需要解析节点
b.同步返回代码如下,其实业务逻辑与异步通知一样,主要就是获取数据有区别,是GET方式获取
8.如果以上呜呜,恭喜你成功了,不得不说一句,支付宝接口真的是良心产品,官方DEMO也是非常完善