苏飞论坛
标题: 支付宝及时到帐接口使用详解 [打印本页]
作者: yangying 时间: 2012-7-29 07:21
标题: 支付宝及时到帐接口使用详解
这两天写支付宝接口, 这个话题不新了, 因为很多人都 做过了, 在这里我说说我的看法吧, 先说一下实现
其实支付宝公司已经给我们做的很好了, 只要少量的改动就OK了,只是有的程序员不太明天他们的动作流程而以,我就以及时到帐为例子来说了,呵呵
在这之前就大家先下载一下c#版的及时到帐代码
先看一下程序的结构吧
(, 下载次数: 836)
支付宝有一个类文件叫 AliPay 是一些加密算法之类的东西,包括构造URL
要吧看一下这个类的全部内容
[C#] 纯文本查看 复制代码
using System.Web;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Net;
using System;
/// <summary>
/// New Interface for AliPay
/// </summary>
namespace Gateway
{
public class AliPay
{
/// <summary>
/// 与ASP兼容的MD5加密算法
/// </summary>
public static string GetMD5(string s, string _input_charset)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] t = md5.ComputeHash(Encoding.GetEncoding(_input_charset).GetBytes(s));
StringBuilder sb = new StringBuilder(32);
for (int i = 0; i < t.Length; i++)
{
sb.Append(t.ToString("x").PadLeft(2, '0'));
}
return sb.ToString();
}
/// <summary>
/// 冒泡排序法
/// 按照字母序列从a到z的顺序排列
/// </summary>
public static string[] BubbleSort(string[] r)
{
int i, j; //交换标志
string temp;
bool exchange;
for (i = 0; i < r.Length; i++) //最多做R.Length-1趟排序
{
exchange = false; //本趟排序开始前,交换标志应为假
for (j = r.Length - 2; j >= i; j--)
{//交换条件
if (System.String.CompareOrdinal(r[j + 1], r[j]) < 0)
{
temp = r[j + 1];
r[j + 1] = r[j];
r[j] = temp;
exchange = true; //发生了交换,故将交换标志置为真
}
}
if (!exchange) //本趟排序未发生交换,提前终止算法
{
break;
}
}
return r;
}
/// <summary>
/// 生成URL链接或加密结果
/// </summary>
/// <param name="para">参数加密数组</param>
/// <param name="_input_charset">编码格式</param>
/// <param name="sign_type">加密类型</param>
/// <param name="key">安全校验码</param>
/// <returns>字符串URL或加密结果</returns>
public static string CreatUrl(
//string gateway,//GET方式传递参数时请去掉注释
string[] para,
string _input_charset,
string sign_type,
string key
)
{
int i;
//进行排序;
string[] Sortedstr = BubbleSort(para);
//构造待md5摘要字符串 ;
StringBuilder prestr = new StringBuilder();
for (i = 0; i < Sortedstr.Length; i++)
{
if (i == Sortedstr.Length - 1)
{
prestr.Append(Sortedstr);
}
else
{
prestr.Append(Sortedstr + "&");
}
}
prestr.Append(key);
//生成Md5摘要;
string sign = GetMD5(prestr.ToString(), _input_charset);
//以下是POST方式传递参数
return sign;
//以下是GET方式传递参数
//构造支付Url;
// char[] delimiterChars = { '='};
// StringBuilder parameter = new StringBuilder();
// parameter.Append(gateway);
// for (i = 0; i < Sortedstr.Length; i++)
// {//UTF-8格式的编码转换
// parameter.Append(Sortedstr.Split(delimiterChars)[0] + "=" + HttpUtility.UrlEncode(Sortedstr.Split(delimiterChars)[1]) + "&");
// }
//
// parameter.Append("sign=" + sign + "&sign_type=" + sign_type);
//
// //返回支付Url;
// return parameter.ToString();
}
//获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
public static string Get_Http(string a_strUrl, int timeout)
{
string strResult;
try
{
HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(a_strUrl);
myReq.Timeout = timeout;
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
Stream myStream = HttpWResp.GetResponseStream();
StreamReader sr = new StreamReader(myStream, Encoding.Default);
StringBuilder strBuilder = new StringBuilder();
while (-1 != sr.Peek())
{
strBuilder.Append(sr.ReadLine());
}
strResult = strBuilder.ToString();
}
catch (Exception exp)
{
strResult = "错误:" + exp.Message;
}
return strResult;
}
}
}
而我们一般不用管这个类,只要保证能调用 的到就行了,不用管他
我们要做的很少,他是怎么工作的呢,
(, 下载次数: 720)
这是开发文档里的工作图
其实我们要处理的只有三个Aspx的文件,
先看第一个吧 Default.aspx
这是一个请求的界面
[C#] 纯文本查看 复制代码
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Gateway;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void BtnAlipay_Click(object sender, EventArgs e)
{
//业务参数赋值;
string gateway = "https://www.alipay.com/cooperate/gateway.do?"; //支付接口
string service = "create_direct_pay_by_user"; //服务名称,这个是识别是何接口实现何功能的标识,请勿修改
string seller_email = "写自己的"; //商家签约时的支付宝帐号,即收款的支付宝帐号
string sign_type = "MD5"; //加密类型,签名方式“不用改”
string key = "写自己的"; //安全校验码,与partner是一组,获取方式是:用签约时支付宝帐号登陆支付宝网站www.alipay.com,在商家服务我的商家里即可查到。
string partner = "写自己的"; //商户ID,合作身份者ID,合作伙伴ID
string _input_charset = "utf-8"; //编码类型,完全根据客户自身的项目的编码格式而定,千万不要填错。否则极其容易造成MD5加密错误。
string show_url = "http://www.alipay.com/"; //展示地址,即在支付页面时,商品名称旁边的“详情”的链接地址。
string out_trade_no = TxtOrderno.Text.Trim(); //客户自己的订单号,订单号必须在自身订单系统中保持唯一性
string subject = "4.0系统支付宝充值"; //商品名称,也可称为订单名称,该接口并不是单一的只能买一样东西,可把一次支付当作一次下订单
string body = "商户:" + TxtOrderno.Text.Trim() + "通过支付宝给自己充值:" + TxtTotal_fee.Text.Trim() + "元"; //商品描述,即备注
string total_fee = TxtTotal_fee.Text.Trim(); //商品价格,也可称为订单的总金额
//服务器通知url(Alipay_Notify.aspx文件所在路经),必须是完整的路径地址
string notify_url = http://0.0.6.108/Alipay/Alipay_Notify.aspx;
//服务器返回url(Alipay_Return.aspx文件所在路经),必须是完整的路径地址
string return_url = http://0.0.6.108/Alipay/Alipay_Return.aspx;
//构造数组;
//以下数组即是参与加密的参数,若参数的值不允许为空,若该参数为空,则不要成为该数组的元素
string[] para ={
"service="+service,
"partner=" + partner,
"seller_email=" + seller_email,
"out_trade_no=" + out_trade_no,
"subject=" + subject,
"body=" + body,
"total_fee=" + total_fee,
"show_url=" + show_url,
"payment_type=1",
"notify_url=" + notify_url,
"return_url=" + return_url,
"_input_charset="+_input_charset
};
//支付URL生成
string aliay_url = AliPay.CreatUrl(
//gateway,//GET方式传递参数时请去掉注释
para,
_input_charset,
sign_type,
key
);
//以下是GET方式传递参数
//Response.Redirect(aliay_url);
//以下是POST方式传递参数
Response.Write("<form name='alipaysubmit' method='post' action='https://www.alipay.com/cooperate/gateway.do?_input_charset=utf-8'>");
Response.Write("<input type='hidden' name='service' value=" + service + ">");
Response.Write("<input type='hidden' name='partner' value=" + partner + ">");
Response.Write("<input type='hidden' name='seller_email' value=" + seller_email + ">");
Response.Write("<input type='hidden' name='out_trade_no' value=" + out_trade_no + ">");
Response.Write("<input type='hidden' name='subject' value=" + subject + ">");
Response.Write("<input type='hidden' name='body' value=" + body + ">");
Response.Write("<input type='hidden' name='total_fee' value=" + total_fee + ">");
Response.Write("<input type='hidden' name='show_url' value=" + show_url + ">");
Response.Write("<input type='hidden' name='return_url' value=" + return_url + ">");
Response.Write("<input type='hidden' name='notify_url' value=" + notify_url + ">");
Response.Write("<input type='hidden' name='payment_type' value=1>");
Response.Write("<input type='hidden' name='sign' value=" + aliay_url + ">");
Response.Write("<input type='hidden' name='sign_type' value=" + sign_type + ">");
Response.Write("</form>");
Response.Write("<script>");
Response.Write("document.alipaysubmit.submit()");
Response.Write("</script>");
}
}
代码里的key和 partner的获取方法
(, 下载次数: 723)
现在我们只要按代码里的信息填写一样就可以了,
然后远行网页
点提交
就会进入
(, 下载次数: 727)
下面的操作就是在支付平台的完成了, 跟咱的程序没有关系了
现在我们应该想,那付完钱之后呢?
我们有两个界面来处理这个问题一个是
Alipay_Return.aspx
[C#] 纯文本查看 复制代码
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Collections.Specialized;
using System.IO;
using Gateway;
/// <summary>
/// 创建该页面文件时,请留心该页面文件是可以对其进行美工处理的,原因在于支付完成以后,当前窗口会从支付宝的页面跳转回这个页面。
/// 该页面称作“返回页”,是同步被支付宝服务器所调用,可当作是支付完成后的提示信息页,如“您的某某某订单,多少金额已支付成功”。
/// </summary>
public partial class Alipay_Return : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string alipayNotifyURL = "https://www.alipay.com/cooperate/gateway.do?service=notify_verify";
//string alipayNotifyURL = "http://notify.alipay.com/trade/notify_query.do?";//此路径是在上面链接地址无法起作用时替换使用。
string key = "写自己的"; //partner 的对应交易安全校验码(必须填写)
string partner = "写自己的"; //partner合作伙伴id(必须填写)
string _input_charset = "utf-8";//编码类型,完全根据客户自身的项目的编码格式而定,千万不要填错。否则极其容易造成MD5加密错误。
alipayNotifyURL = alipayNotifyURL + "&partner=" + partner + "¬ify_id=" + Request.QueryString["notify_id"];
//获取支付宝ATN返回结果,true是正确的订单信息,false 是无效的
string responseTxt = AliPay.Get_Http(alipayNotifyURL, 120000);
//*******加密签名程序开始//*******
int i;
NameValueCollection coll;
//Load Form variables into NameValueCollection variable.
coll = Request.QueryString;
// Get names of all forms into a string array.
String[] requestarr = coll.AllKeys;
//进行排序;
string[] Sortedstr = AliPay.BubbleSort(requestarr);
//构造待md5摘要字符串 ;
StringBuilder prestr = new StringBuilder();
for (i = 0; i < Sortedstr.Length; i++)
{
if (Request.Form[Sortedstr] != "" && Sortedstr != "sign" && Sortedstr != "sign_type")
{
if (i == Sortedstr.Length - 1)
{
prestr.Append(Sortedstr + "=" + Request.QueryString[Sortedstr]);
}
else
{
prestr.Append(Sortedstr + "=" + Request.QueryString[Sortedstr] + "&");
}
}
}
prestr.Append(key);
//生成Md5摘要;
string mysign = AliPay.GetMD5(prestr.ToString(), _input_charset);
//*******加密签名程序结束*******
string sign = Request.QueryString["sign"];
// Response.Write(prestr.ToString()); //调试用,支付宝服务器返回时的完整路径。
if (mysign == sign && responseTxt == "true") //验证支付发过来的消息,签名是否正确
{
//更新自己数据库的订单语句,请自己填写一下
string strOrderNO = Request.QueryString["out_trade_no"];//订单号
string strPrice = Request.QueryString["total_fee"];//金额
string strTradeStatus = Request.QueryString["TRADE_STATUS"];//订单状态
//以下都是自己处理订单的方法了最后才要输出如下内容
Response.Write("商户:" + login[1].ToString().Trim() + "<br>金额:" + strPrice + " 交易成功"); //成功,可美化该页面,提示信息
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt + " 交易信息" + "商户:" + login[1].ToString().Trim() + "<br>金额:" + strPrice + " 交易成功";
StreamWriter fs = new StreamWriter(Server.MapPath("Return_DATA/" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default);
fs.Write(TOEXCELLR);
fs.Close();
}
else
{
Response.Write("------------------------------------------");
Response.Write("<br>Result:responseTxt=" + responseTxt);
Response.Write("<br>Result:mysign=" + mysign);
Response.Write("<br>Result:sign=" + sign);
Response.Write("支付失败");
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt;
StreamWriter fs = new StreamWriter(Server.MapPath("Return_DATA/" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default);
fs.Write(TOEXCELLR);
fs.Close();
//支付失败,提示信息
}
}
}
这个是当交易成功后要调用 的界面 在这里只要改动一下就行了, 其实我们要做的只是改一下这里,只要在这里更新一下你的数据库就行了
[C#] 纯文本查看 复制代码
//生成对象
//OfficeFinanceServices objOfficeFinanceServices = new OfficeFinanceServices();
//订单信息
string[] login = strOrderNO.Split(new string[] { "_" }, StringSplitOptions.RemoveEmptyEntries);
////查询当前的余额
//decimal objdm = objOfficeFinanceServices.OfficeFinanceSelect(Convert.ToInt32(login[0].ToString().Trim()), true);
//OfficeFinance objofficeFinance = new OfficeFinance();
//objofficeFinance.ofId = Convert.ToInt32(login[0].ToString().Trim());
//objofficeFinance.ofOrid = "cz";
//objofficeFinance.ofTime = DateTime.Now;
//objofficeFinance.ofType = 1;
//objofficeFinance.ofAmount = Convert.ToDecimal(strPrice.ToString().Trim());
//objofficeFinance.ofRemainAmount = Convert.ToDecimal(strPrice.ToString().Trim()) + objdm;
//objofficeFinance.ofIsCurrentValue = 1;
//objofficeFinance.ofUserId = -10;
//objofficeFinance.ofNote1 = "支付宝上帐:" + strPrice.ToString().Trim() + "元";
//objofficeFinance.ofNote2 = "商户:" + login[1].ToString().Trim() + " 通过支付宝上帐金额:" + strPrice + "元";
//objOfficeFinanceServices.addOfficeFinanceOne(objofficeFinance);
大家现在会问我为什么会把他们注释了呢?
我测试过,,这个界面呢是只到成功的时候 调用 一次以后就再不会调用 了,
所以这样有一个不好的地方 ,就是有些客户他们对转帐操作的很老手,当交易成功之后不等调用这个界面就关闭了浏览器,这个时候会出现什么问题呢?
那支付宝就再也不会调用这个界面 了,只能等下次交易,钱是打上了,我们也收到了,但是就是没有给客户充上钱,这个时候客户就会打电话到公司,怎么回事啊, 钱打过去了, 可是我这边还没有上帐,我们上支付宝一看有啊,但就是没有上帐 ,怎么办,最后只能手动给客户上了,但又怕他程序再自动上一把,呵呵
所以在这里不我建议使用这个页面,如果你只是修改自己的订单状态的话当然是可以的
修改余额就不要在这里写了,而是写在这个Alipay_Notify.aspx页面里,这个界面是当交易状态 发生变化时就会调用 ,在没有收到成功的消息前就会一直调用,
时效是24小时,这样的话我们就不用管他是不是转到了成功页面了,只要把这个页面挂在网上等通知就行了,
当交易成功的时候上帐 就OK了
[C#] 纯文本查看 复制代码
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Collections.Specialized;
using System.IO;
using Gateway;
using SystemModel;
/// <summary>
/// 创建该页面文件时,请留心该页面文件中无任何HTML代码及空格。
/// 该页面称作“通知页”,是异步被支付宝服务器所调用。
/// 当支付宝的订单状态改变时,支付宝服务器则会自动调用此页面,因此请做好自身网站订单信息与支付宝上的订单的同步工作
/// </summary>
public partial class Alipay_Notify : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string alipayNotifyURL = "https://www.alipay.com/cooperate/gateway.do?service=notify_verify";
//string alipayNotifyURL = "http://notify.alipay.com/trade/notify_query.do?";//此路径是在上面链接地址无法起作用时替换使用。
string partner = "写自己的"; //partner合作伙伴id(必须填写)
string key = "写自己的"; //partner 的对应交易安全校验码(必须填写)
string _input_charset = "utf-8";//编码类型,完全根据客户自身的项目的编码格式而定,千万不要填错。否则极其容易造成MD5加密错误。
alipayNotifyURL = alipayNotifyURL + "&partner=" + partner + "¬ify_id=" + Request.Form["notify_id"];
//获取支付宝ATN返回结果,true是正确的订单信息,false 是无效的
string responseTxt = AliPay.Get_Http(alipayNotifyURL, 120000);
//*******加密签名程序开始*******
int i;
NameValueCollection coll;
//Load Form variables into NameValueCollection variable.
coll = Request.Form;
// Get names of all forms into a string array.
String[] requestarr = coll.AllKeys;
//进行排序;
string[] Sortedstr = AliPay.BubbleSort(requestarr);
//构造待md5摘要字符串 ;
StringBuilder prestr = new StringBuilder();
for (i = 0; i < Sortedstr.Length; i++)
{
if (Request.Form[Sortedstr] != "" && Sortedstr != "sign" && Sortedstr != "sign_type")
{
if (i == Sortedstr.Length - 1)
{
prestr.Append(Sortedstr + "=" + Request.Form[Sortedstr]);
}
else
{
prestr.Append(Sortedstr + "=" + Request.Form[Sortedstr] + "&");
}
}
}
prestr.Append(key);
string mysign = AliPay.GetMD5(prestr.ToString(), _input_charset);
//*******加密签名程序结束*******
string sign = Request.Form["sign"];
if (mysign == sign && responseTxt == "true") //验证支付发过来的消息,签名是否正确,只要成功进如这个判断里,则表示该页面已被支付宝服务器成功调用
//但判断内出现自身编写的程序相关错误导致通知给支付宝并不是发送success的消息或没有更新客户自身的数据库的情况,请自身程序编写好应对措施,否则查明原因时困难之极
{
if (Request.Form["trade_status"] == "WAIT_BUYER_PAY")// 判断支付状态_等待买家付款(文档中有枚举表可以参考)
{
//更新自己数据库的订单语句,请自己填写一下
string strOrderNO = Request.Form["out_trade_no"];//订单号
string strPrice = Request.Form["total_fee"];//金额 如果你申请了商家购物卷功能,在返回信息里面请不要做金额的判断,否则会校验通过不了。
string TOEXCELL = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt;
StreamWriter f = new StreamWriter(Server.MapPath("Notify_DATA/" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default);
f.Write(TOEXCELL + "订单号:" + strOrderNO.ToString().Trim() + " 金额:" + strPrice.ToString().Trim());
f.Close();
//以下是我处理自己的订单状态
Alipaym objalipay = new Alipaym();
objalipay.APID = strOrderNO;
objalipay.addTime = DateTime.Now;
objalipay.total_fee = Convert.ToDecimal(strPrice);
objalipay.trade_status = "等待买家付款";
objalipay.Text1 = DateTime.Now.ToString();
objalipay.Text2 = "";
objalipay.Text3 = "";
objalipay.Text4 = "";
objalipay.Text5 = "";
OfficeFinanceServices.Update(objalipay);
}
else if (Request.Form["trade_status"] == "TRADE_FINISHED" || Request.Form["trade_status"] == "TRADE_SUCCESS")// 判断支付状态_交易成功结束(文档中有枚举表可以参考)
{
//更新自己数据库的订单语句,请自己填写一下
string strOrderNO = Request.Form["out_trade_no"];//订单号
string strPrice = Request.Form["total_fee"];//金额
//生成对象
OfficeFinanceServices objOfficeFinanceServices = new OfficeFinanceServices();
//订单信息
string[] login = strOrderNO.Split(new string[] { "_" }, StringSplitOptions.RemoveEmptyEntries);
////查询当前的余额
decimal objdm = objOfficeFinanceServices.OfficeFinanceSelect(Convert.ToInt32(login[0].ToString().Trim()), true);
OfficeFinance objofficeFinance = new OfficeFinance();
objofficeFinance.ofId = Convert.ToInt32(login[0].ToString().Trim());
objofficeFinance.ofOrid = "cz";
objofficeFinance.ofTime = DateTime.Now;
objofficeFinance.ofType = 1;
objofficeFinance.ofAmount = Convert.ToDecimal(strPrice.ToString().Trim());
objofficeFinance.ofRemainAmount = Convert.ToDecimal(strPrice.ToString().Trim()) + objdm;
objofficeFinance.ofIsCurrentValue = 1;
objofficeFinance.ofUserId = -10;
objofficeFinance.ofNote1 = "支付宝上帐:" + strPrice.ToString().Trim() + "元";
objofficeFinance.ofNote2 = "商户:" + login[1].ToString().Trim() + " 通过支付宝上帐金额:" + strPrice + "元";
if (objOfficeFinanceServices.addOfficeFinanceOne(objofficeFinance))
{
Response.Write("success");
Alipaym objalipay = new Alipaym();
objalipay.APID = strOrderNO;
objalipay.addTime = DateTime.Now;
objalipay.total_fee = Convert.ToDecimal(strPrice);
objalipay.trade_status = "交易成功";
objalipay.Text1 = DateTime.Now.ToString();
objalipay.Text2 = "";
objalipay.Text3 = "";
objalipay.Text4 = "";
objalipay.Text5 = "";
OfficeFinanceServices.Update(objalipay);
}
else
{
Response.Write("fail");
}
}
else
{
//更新自己数据库的订单语句,请自己填写一下
}
//Response.Write("success"); //返回给支付宝消息,成功,请不要改写这个success
//success与fail及其他字符的区别在于,支付宝的服务器若遇到success时,则不再发送请求通知(即不再调用该页面,让该页面再次运行起来),
//若不是success,则支付宝默认没有收到成功的信息,则会反复不停地调用该页面直到失效,有效调用时间是24小时以内。
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt;
StreamWriter fs = new StreamWriter(Server.MapPath("Notify_DATA/" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default);
fs.Write(TOEXCELLR);
fs.Close();
}
else
{
Response.Write("fail");
//写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt;
StreamWriter fs = new StreamWriter(Server.MapPath("Notify_DATA/" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default);
fs.Write(TOEXCELLR);
fs.Close();
}
}
}
最好是记录一下日志文件,这样一但出了问题还可以有个参考的地方
我的代码写的有点乱大家可以适当的改一下,呵呵
短短两年的时间,我公司也写过不少接口方面的东东了,在这里和大家分享我的心得和体会,一般人一说到和什么接口对接可能会感觉 到很难,或是感觉很利害的样子,如果是和银行的接口对接,那首先想到的就是安全问题,再就是技术含量,其实不然,接口的产生是为了方便双方的合作,基本没有听说过有那两家公司因为程序对接 不上而放弃合作的,基本没有,都是其它方面的原因,接口是为了方便对接和不同公司和程序之间的交互和通信的,都是为了方便,不是我们想像的那样难,高技术含量,要说技术含量吧也是有一些
我根据自己的开发心得总结一下吧
这种方式的做法是,服务方提供一个方法,但是一般会在第一个参数或是最后一个参数验证一下加密串,这个加密串一般是用所传的参数组合加密而来,最常见的就是MD5加密了,像支付宝的就是。我把这一类型的看做是最低级的一种,因为这种是最不安全的,只要我知道了你的加密算法和后就可以自己改动参数了
对于Http的方法最重要的只有一个方法
[C#] 纯文本查看 复制代码
/// <summary>
/// 请求指定 URL 资源,并获取响应结果
/// </summary>
/// <param name="url">需要请求的 URL 资源</param>
/// <returns>
/// 响应结果;
/// 出现任意异常,均返回字串"Runtime Error"
/// </returns>
private string RequestContent(string url)
{
string content = string.Empty;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.KeepAlive = false;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default);
content = reader.ReadToEnd();
reader.Close();
}
catch (Exception)
{
content = "Runtime Error";
}
return content;
}
只要我们把要传的参数和URL对接后传给这 个方法就算是完事了,另外在MD5加密是时间注意对方是否要区分大小写,最好是把加密串一下子全转成小写或是大写的
加密的方法一般如下
[C#] 纯文本查看 复制代码
/// <summary>
/// 传入明文,返回用MD%加密后的字符串
/// </summary>
/// <param name="str">要加密的字符串</param>
/// <returns>用MD5加密后的字符串</returns>
public static string ToMD5(string str)
{
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "md5");
}
在做这样的接口的时候一定要注意一定要验证的地方有三点:第一点就是验证加密串了
这里就是把所需要的参数在本地加一下密然后和服务端发来的对比
第二点就是控制页面只在首次加载时执行这个我们可以通过下面的方式来实现
[C#] 纯文本查看 复制代码
if (!IsPostBack)
{
............
}
我们只要在IF块里面写我们的代码就可以了
第三点也是最关键的一点那就是验证一下请求过来的DNS或是IP
就是说你要验证一下发过来请求的来源电脑是不是你的服务商的DNS或是IP,如果不是就可以不执行程序或是提示为非法操作,这样可以防止有人知道了你的加密算法后自己生成一些代码来高乱你的程序给公司带来损失,特别是即使到账的接口,这一点一定要验证好,而且在IIS服务器最好是绑定一下IP,只接收授权的IP发来的消息。这样基本可以保证安全问题了。
好了对于 这种方法我来用一个Http的例子来演示一下吧
[C#] 纯文本查看 复制代码
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Collections.Specialized;
using System.IO;
using Gateway;
using SystemModel;
/// <summary>
/// 创建该页面文件时,请留心该页面文件是可以对其进行美工处理的,原因在于支付完成以后,当前窗口会从支付宝的页面跳转回这个页面。
/// 该页面称作“返回页”,是同步被支付宝服务器所调用,可当作是支付完成后的提示信息页,如“您的某某某订单,多少金额已支付成功”。
/// </summary>
public partial class Alipay_Return : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//生成对象
OfficeFinanceServices objOfficeFinanceServices = new OfficeFinanceServices();
Alipaym objalipay = new Alipaym();
try
{
string alipayNotifyURL = "https://www.alipay.com/cooperate/gateway.do?service=notify_verify";
//string alipayNotifyURL = "http://notify.alipay.com/trade/notify_query.do?";//此路径是在上面链接地址无法起作用时替换使用。
string key = ""; //partner 的对应交易安全校验码(必须填写)
string partner = ""; //partner合作伙伴id(必须填写)
string _input_charset = "utf-8";//编码类型,完全根据客户自身的项目的编码格式而定,千万不要填错。否则极其容易造成MD5加密错误。
alipayNotifyURL = alipayNotifyURL + "&partner=" + partner + "¬ify_id=" + Request.QueryString["notify_id"];
//获取支付宝ATN返回结果,true是正确的订单信息,false 是无效的
string responseTxt = AliPay.Get_Http(alipayNotifyURL, 120000);
//*******加密签名程序开始//*******
int i;
NameValueCollection coll;
//Load Form variables into NameValueCollection variable.
coll = Request.QueryString;
// Get names of all forms into a string array.
String[] requestarr = coll.AllKeys;
//进行排序;
string[] Sortedstr = AliPay.BubbleSort(requestarr);
//构造待md5摘要字符串 ;
StringBuilder prestr = new StringBuilder();
for (i = 0; i < Sortedstr.Length; i++)
{
if (Request.Form[Sortedstr] != "" && Sortedstr != "sign" && Sortedstr != "sign_type")
{
if (i == Sortedstr.Length - 1)
{
prestr.Append(Sortedstr + "=" + Request.QueryString[Sortedstr]);
}
else
{
prestr.Append(Sortedstr + "=" + Request.QueryString[Sortedstr] + "&");
}
}
}
prestr.Append(key);
//生成Md5摘要;
string mysign = AliPay.GetMD5(prestr.ToString(), _input_charset);
//*******加密签名程序结束*******
string sign = Request.QueryString["sign"];
// Response.Write(prestr.ToString()); //调试用,支付宝服务器返回时的完整路径。
if (mysign == sign && responseTxt == "true" && Request.UserHostName == "www.alipay.com") //验证支付发过来的消息,签名是否正确
{
//更新自己数据库的订单语句,请自己填写一下
string strOrderNO = Request.QueryString["out_trade_no"];//订单号
string strPrice = Request.QueryString["total_fee"];//金额
string strTradeStatus = Request.QueryString["TRADE_STATUS"];//订单状态
string result = objOfficeFinanceServices.CheckNo(strOrderNO.ToString().Trim());
if (result.Trim() == "0")
{
//成功,可美化该页面,提示信息
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign +
",responseTxt=" + responseTxt ;
StreamWriter fs = new StreamWriter(Server.MapPath("Return_DATA/" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default);
fs.Write(TOEXCELLR);
fs.Close();
//修改订单状态
}
else if (result == "-1")
{
//修改订单状态
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt + "perky_" + result.Trim() + Request.UserHostName.Trim() + Request.UserHostAddress.Trim();
StreamWriter fs = new StreamWriter(Server.MapPath("Return_DATA/" + "e" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default);
fs.Write(TOEXCELLR);
fs.Close();
Response.Write("查询订单时失败!!! 请确定你是否下单!!!");
}
else
{
//修改订单状态
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt + "perky_" + result.Trim() + Request.UserHostName.Trim() + Request.UserHostAddress.Trim();
StreamWriter fs = new StreamWriter(Server.MapPath("Return_DATA/" + "e" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default);
fs.Write(TOEXCELLR);
fs.Close();
Response.Write("重复使用界面无效!!!");
}
}
else
{
Response.Write("------------------------------------------");
Response.Write("<br>Result:responseTxt=" + responseTxt);
Response.Write("<br>Result:mysign=" + mysign);
Response.Write("<br>Result:sign=" + sign);
Response.Write("支付失败");
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt + Request.UserHostName.Trim() + Request.UserHostAddress.Trim();
StreamWriter fs = new StreamWriter(Server.MapPath("Return_DATA/" + "e" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default);
fs.Write(TOEXCELLR);
fs.Close();
}
}
catch (Exception ex)
{
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
string TOEXCELLR = Request.Url.ToString() + " " + ex.Message.ToString() + Request.UserHostName.Trim() + Request.UserHostAddress.Trim();
StreamWriter fs = new StreamWriter(Server.MapPath("Return_DATA/" + "m" + DateTime.Now.ToString().Replace(":", "")) + ".txt", false, System.Text.Encoding.Default);
fs.Write(TOEXCELLR);
fs.Close();
}
}
}
}
Http的方法有的接口还是要带证书才能实现的
关于这一块的做方法大家请参考一下我的另一个文章
HttpRequest访问Https带有证书并使用WSDL文档生成代理类方案
应该注意的地方
1.验证加密串
2.验证首次加载时执行
3.验证DNS或是IP
4.IIS服务器绑定IP或是DNS
5.一般要在关键的地方记录日志文件,或是存入数据库,要把发过来的请求原封不动的存储一下,一是方便查对,二是一但出现问题这就是证据啊!!!
6.注意一下官方的加密串有没有统一大小写的问题
作者: 剪刀手 时间: 2012-8-1 16:25
膜拜中……
作者: 旻杰 时间: 2012-8-21 09:24
嗯,证书认证,安全性太重要啦~~
作者: whlgjjgyy 时间: 2012-9-28 12:21
ding顶ding顶
作者: terrychen 时间: 2012-10-15 15:32
顶!顶!和官方的有些不一样,是自己封装的么!
作者: 站长苏飞 时间: 2012-10-15 16:11
terrychen 发表于 2012-10-15 15:32
顶!顶!和官方的有些不一样,是自己封装的么!
一部分是自己修改过的,比如官方的更适合一些
作者: SillyPGM 时间: 2012-11-7 13:38
最近自己弄了一个小站,看到这里,我想给自己的小站试试。谢谢LZ分享。
作者: jjloveC# 时间: 2012-11-15 13:00
辛苦了。····我想问问本地可以测试吗
作者: ro4ters 时间: 2013-3-28 23:29
好多文章都看不见..
作者: 猫星人 时间: 2013-6-4 14:21
不错,学习一下,淘宝好像有一个公开平台,还有很多接口啊。。。。叫做APITOP。http://open.taobao.com/index.htm
作者: yangying 时间: 2013-6-4 14:28
是的,这个只是及时到账接口,也算是比较常用的
作者: 望远镜 时间: 2013-6-16 00:47
很好很强大呀
作者: coody 时间: 2013-11-9 11:08
来学习游戏i啊看看!
作者: 孤独男孩 时间: 2014-6-20 13:13
强烈支持楼主ing……
作者: cfan1236 时间: 2014-8-18 14:10
我最近也在做支付宝的对接,是移动端的支付。相对于要负责点,要用RSA算法加密解密。
作者: ching126 时间: 2014-9-9 22:42
强烈支持楼主ing……
作者: Shmily·X 时间: 2014-10-21 14:24
膜拜中....!
作者: liqingboyou 时间: 2015-5-9 09:39
淘宝这个必须申请淘宝API吗?那个必须要商业用户才可以。个人不申请可以直接使用吗?
作者: 451205927 时间: 2015-6-5 09:14
好东西,谢谢分享。
作者: zhengbai008 时间: 2015-9-9 20:18
楼主太厉害了
作者: aniuge 时间: 2016-8-9 09:57
好的,非常不错
作者: 1022heisige 时间: 2020-10-28 11:36
好厉害啊,微信的有吗?还有就是免费的吗?
欢迎光临 苏飞论坛 (http://www.sufeinet.com/) |
Powered by Discuz! X3.4 |