C#【支付宝】网页端支付流程(三)

版权声明: https://blog.csdn.net/liuchang19950703/article/details/81905036

后台配置接入支付宝申请支付:

附上支付宝接口API统一支付文档:

alipay.trade.page.pay更新时间:2017-11-02

PC场景下单并支付

公共参数

请求地址:

环境 HTTPS请求地址
正式环境 https://openapi.alipay.com/gateway.do

公共请求参数:

参数 类型 是否必填 最大长度 描述 示例值
app_id String 32 支付宝分配给开发者的应用ID 2014072300007148
method String 128 接口名称 alipay.trade.page.pay
format String 40 仅支持JSON JSON
return_url String 256 同步返回地址,HTTP/HTTPS开头字符串 https://m.alipay.com/Gk8NF23
charset String 10 请求使用的编码格式,如utf-8,gbk,gb2312等 utf-8
sign_type String 10 商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2 RSA2
sign String 256 商户请求参数的签名串,详见签名 详见示例
timestamp String 19 发送请求的时间,格式"yyyy-MM-dd HH:mm:ss" 2014-07-24 03:07:50
version String 3 调用的接口版本,固定为:1.0 1.0
notify_url String 256 支付宝服务器主动通知商户服务器里指定的页面http/https路径。 https://api.xx.com/receive_notify.htm
biz_content String - 业务请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递,具体参照各产品快速接入文档  

请求参数

参数

类型

是否必填

最大长度

描述

示例值

out_trade_no

扫描二维码关注公众号,回复: 3015353 查看本文章

String

64

商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复

20150320010101001

product_code

String

64

销售产品码,与支付宝签约的产品码名称。 注:目前仅支持FAST_INSTANT_TRADE_PAY

FAST_INSTANT_TRADE_PAY

total_amount

Price

11

订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]

88.88

subject

String

256

订单标题

Iphone6 16G

body

String

128

订单描述

Iphone6 16G

goods_detail

String

 

订单包含的商品列表信息,Json格式: {"show_url":"https://或http://打头的商品的展示地址"} ,在支付时,可点击商品名称跳转到该地址

{"show_url":"https://www.alipay.com"}

passback_params

String

512

公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。支付宝只会在异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付宝

merchantBizType%3d3C%26merchantBizNo%3d2016010101111

extend_params

String

 

业务扩展参数,详见业务扩展参数说明

{"sys_service_provider_id":"2088511833207846"}

goods_type

String

2

商品主类型:0—虚拟类商品,1—实物类商品(默认)
注:虚拟类商品不支持使用花呗渠道

0

timeout_express

String

6

该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m。

该参数在请求到支付宝时开始计时。

90m

enable_pay_channels

String

128

可用渠道,用户只能在指定渠道范围内支付
当有多个渠道时用“,”分隔
注:与disable_pay_channels互斥

pcredit,moneyFund,debitCardExpress

disable_pay_channels

String

128

禁用渠道,用户不可用指定渠道支付
当有多个渠道时用“,”分隔
注:与enable_pay_channels互斥

pcredit,moneyFund,debitCardExpress

auth_token

String

40

获取用户授权信息,可实现如免登功能。获取方法请查阅:用户信息授权

appopenBb64d181d0146481ab6a762c00714cC27

qr_pay_mode

String

2

PC扫码支付的方式,支持前置模式和跳转模式。
前置模式是将二维码前置到商户的订单确认页的模式。需要商户在自己的页面中以iframe方式请求支付宝页面。具体分为以下几种:
0:订单码-简约前置模式,对应iframe宽度不能小于600px,高度不能小于300px;
1:订单码-前置模式,对应iframe宽度不能小于300px,高度不能小于600px;
3:订单码-迷你前置模式,对应iframe宽度不能小于75px,高度不能小于75px;
4:订单码-可定义宽度的嵌入式二维码,商户可根据需要设定二维码的大小。

跳转模式下,用户的扫码界面是由支付宝生成的,不在商户的域名下。
2:订单码-跳转模式

4

qrcode_width

String

4

商户自定义二维码宽度

注:qr_pay_mode=4时该参数生效

100

业务扩展参数说明

参数 类型 是否必填 最大长度 描述 示例值
sys_service_provider_id String 64 系统商编号,该参数作为系统商返佣数据提取的依据,请填写系统商签约协议的PID 2088511833207846
hb_fq_num String 5 花呗分期数(目前仅支持3、6、12)注:使用该参数需要仔细阅读“花呗分期接入文档 3
hb_fq_seller_percent String 3 卖家承担收费比例,商家承担手续费传入100,用户承担手续费传入0,仅支持传入100、0两种,其他比例暂不支持注:使用该参数需要仔细阅读“花呗分期接入文档 100

渠道说明

渠道名称 说明
balance 余额
moneyFund 余额宝
coupon 红包
pcredit 花呗
pcreditpayInstallment 花呗分期
creditCard 信用卡
creditCardExpress 信用卡快捷
creditCardCartoon 信用卡卡通
credit_group 信用支付类型(包含信用卡卡通、信用卡快捷、花呗、花呗分期)
debitCardExpress 借记卡快捷
mcard 商户预存卡
pcard 个人预存卡
promotion 优惠(包含实时优惠+商户优惠)
voucher 营销券
point 积分
mdiscount 商户优惠
bankPay 网银

一.后台代码部分:

1:AlipayConfig类文件:配置对接接口的参数

using System.Web;
using System.Text;
using System.IO;
using System.Net;
using System;
using System.Collections.Generic;

namespace CS
{
    /// <summary>
    /// 类名:Config
    /// 功能:基础配置类
    /// 详细:设置帐户有关信息及返回路径
    /// 版本:3.4
    /// 修改日期:2016-03-08
    /// 说明:
    /// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
    /// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
    /// </summary>
    public class AlipayConfig
    {

        //↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

        // 合作身份者ID,签约账号,以2088开头由16位纯数字组成的字符串,查看地址:https://b.alipay.com/order/pidAndKey.htm

      

        public static string partner = "208800113*******";

        // 收款支付宝账号,以2088开头由16位纯数字组成的字符串,一般情况下收款账号就是签约账号
        public static string seller_id = partner;

        // MD5密钥,安全检验码,由数字和字母组成的32位字符串,查看地址:https://b.alipay.com/order/pidAndKey.htm
        public static string key = "ka8xyya5st6t***********";

        // 服务器异步通知页面路径,需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
        public static string notify_url = "http://****.com/aliPay/notify_url.aspx";

        // 页面跳转同步通知页面路径,需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
        public static string return_url = "http://****.com/aliPay/return_url.aspx";

        // 签名方式
        public static string sign_type = "MD5";

        // 调试用,创建TXT日志文件夹路径,见AlipayCore.cs类中的LogResult(string sWord)打印方法。
        public static string log_path = HttpRuntime.AppDomainAppPath.ToString() + "log\\";

        // 字符编码格式 目前支持 gbk 或 utf-8
        public static string input_charset = "utf-8";

        // 支付类型 ,无需修改
        public static string payment_type = "1";

        // 调用的接口名,无需修改
        public static string service = "create_direct_pay_by_user";

        //↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
        //↓↓↓↓↓↓↓↓↓↓请在这里配置防钓鱼信息,如果没开通防钓鱼功能,请忽视不要填写 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

        //防钓鱼时间戳  若要使用请调用类文件submit中的Query_timestamp函数
        public static string anti_phishing_key = "";

        //客户端的IP地址 非局域网的外网IP地址,如:221.0.0.1
        public static string exter_invoke_ip = "";

        //↑↑↑↑↑↑↑↑↑↑请在这里配置防钓鱼信息,如果没开通防钓鱼功能,请忽视不要填写 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

        #region 支付宝返回的交易状态
        //交易状态:
        //WAIT_BUYER_PAY(交易创建,等待买家付款)、
        //TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、
        //TRADE_SUCCESS(交易支付成功)、
        //TRADE_FINISHED(交易结束,不可退款)
        public static string WAIT_BUYER_PAY = "交易创建,等待买家付款";
        public static string TRADE_CLOSED = "未付款交易超时关闭,或支付完成后全额退款";
        public static string TRADE_SUCCESS = "交易支付成功";
        public static string TRADE_FINISHED = "交易结束,不可退款";
        #endregion


    }


}

2:AlipayCore类文件:   请求、通知返回两个文件所调用的公用函数核心处理文件,不需要修改

using System.Web;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Net;
using System;
using System.Collections.Generic;
using System.Xml;

namespace CS
{
    /// <summary>
    /// 类名:Core
    /// 功能:支付宝接口公用函数类
    /// 详细:该类是请求、通知返回两个文件所调用的公用函数核心处理文件,不需要修改
    /// 版本:3.4
    /// 修改日期:2016-03-08
    /// 说明:
    /// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
    /// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
    /// </summary>
    public class AlipayCore
    {

        public AlipayCore()
        {
        }

        /// <summary>
        /// 除去数组中的空值和签名参数并以字母a到z的顺序排序
        /// </summary>
        /// <param name="dicArrayPre">过滤前的参数组</param>
        /// <returns>过滤后的参数组</returns>
        public static Dictionary<string, string> FilterPara(SortedDictionary<string, string> dicArrayPre)
        {
            Dictionary<string, string> dicArray = new Dictionary<string, string>();
            foreach (KeyValuePair<string, string> temp in dicArrayPre)
            {
                if (temp.Key.ToLower() != "sign" && temp.Key.ToLower() != "sign_type" && temp.Value != "" && temp.Value != null)
                {
                    dicArray.Add(temp.Key, temp.Value);
                }
            }
            return dicArray;
        }

        /// <summary>
        /// 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
        /// </summary>
        /// <param name="sArray">需要拼接的数组</param>
        /// <returns>拼接完成以后的字符串</returns>
        public static string CreateLinkString(Dictionary<string, string> dicArray)
        {
            StringBuilder prestr = new StringBuilder();
            foreach (KeyValuePair<string, string> temp in dicArray)
            {
                prestr.Append(temp.Key + "=" + temp.Value + "&");
            }
            //去掉最後一個&字符
            int nLen = prestr.Length;
            prestr.Remove(nLen - 1, 1);
            return prestr.ToString();
        }

        /// <summary>
        /// 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对参数值做urlencode
        /// </summary>
        /// <param name="sArray">需要拼接的数组</param>
        /// <param name="code">字符编码</param>
        /// <returns>拼接完成以后的字符串</returns>
        public static string CreateLinkStringUrlencode(Dictionary<string, string> dicArray, Encoding code)
        {
            StringBuilder prestr = new StringBuilder();
            foreach (KeyValuePair<string, string> temp in dicArray)
            {
                prestr.Append(temp.Key + "=" + HttpUtility.UrlEncode(temp.Value, code) + "&");
            }

            //去掉最後一個&字符
            int nLen = prestr.Length;
            prestr.Remove(nLen - 1, 1);
            return prestr.ToString();
        }

        /// <summary>
        /// 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
        /// </summary>
        /// <param name="sWord">要写入日志里的文本内容</param>
        public static void LogResult(string sWord)
        {
            string strPath = AlipayConfig.log_path + "\\" + "alipay_log_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt";
            StreamWriter fs = new StreamWriter(strPath, false, System.Text.Encoding.Default);
            fs.Write(sWord);
            fs.Close();
        }

        /// <summary>
        /// 获取文件的md5摘要
        /// </summary>
        /// <param name="sFile">文件流</param>
        /// <returns>MD5摘要结果</returns>
        public static string GetAbstractToMD5(Stream sFile)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] result = md5.ComputeHash(sFile);
            StringBuilder sb = new StringBuilder(32);
            for (int i = 0; i < result.Length; i++)
            {
                sb.Append(result[i].ToString("x").PadLeft(2, '0'));
            }
            return sb.ToString();
        }

        /// <summary>
        /// 获取文件的md5摘要
        /// </summary>
        /// <param name="dataFile">文件流</param>
        /// <returns>MD5摘要结果</returns>
        public static string GetAbstractToMD5(byte[] dataFile)
        {
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] result = md5.ComputeHash(dataFile);
            StringBuilder sb = new StringBuilder(32);
            for (int i = 0; i < result.Length; i++)
            {
                sb.Append(result[i].ToString("x").PadLeft(2, '0'));
            }
            return sb.ToString();
        }
    }
}

3:AlipayNotify类文件: 处理支付宝各接口通知返回

using System.Web;
using System.Text;
using System.IO;
using System.Net;
using System;
using System.Collections.Generic;


namespace CS
{
    /// <summary>
    /// 类名:Notify
    /// 功能:支付宝通知处理类
    /// 详细:处理支付宝各接口通知返回
    /// 版本:3.3
    /// 修改日期:2011-07-05
    /// '说明:
    /// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
    /// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
    /// 
    /// //////////////////////注意/////////////////////////////
    /// 调试通知返回时,可查看或改写log日志的写入TXT里的数据,来检查通知返回是否正常 
    /// </summary>
    public class AlipayNotify
    {
        #region 字段
        private string _partner = "";               //合作身份者ID
        private string _key = "";                   //商户的私钥
        private string _input_charset = "";         //编码格式
        private string _sign_type = "";             //签名方式

        //支付宝消息验证地址
        private string Https_veryfy_url = "https://mapi.alipay.com/gateway.do?service=notify_verify&";
        #endregion

        /// <summary>
        /// 构造函数
        /// 从配置文件中初始化变量
        /// </summary>
        /// <param name="inputPara">通知返回参数数组</param>
        /// <param name="notify_id">通知验证ID</param>
        public AlipayNotify()
        {
            //初始化基础配置信息
            _partner = AlipayConfig.partner.Trim();
            _key = AlipayConfig.key.Trim();
            _input_charset = AlipayConfig.input_charset.Trim().ToLower();
            _sign_type = AlipayConfig.sign_type.Trim().ToUpper();
        }
		
		 /// <summary>
        /// 从文件读取公钥转公钥字符串
        /// </summary>
        /// <param name="Path">公钥文件路径</param>
        public static string getPublicKeyStr(string Path)
        {
            StreamReader sr = new StreamReader(Path);
            string pubkey = sr.ReadToEnd();
            sr.Close();
            if (pubkey != null)
            {
                pubkey = pubkey.Replace("-----BEGIN PUBLIC KEY-----", "");
                pubkey = pubkey.Replace("-----END PUBLIC KEY-----", "");
                pubkey = pubkey.Replace("\r", "");
                pubkey = pubkey.Replace("\n", "");
            }
            return pubkey;
        }

        /// <summary>
        ///  验证消息是否是支付宝发出的合法消息
        /// </summary>
        /// <param name="inputPara">通知返回参数数组</param>
        /// <param name="notify_id">通知验证ID</param>
        /// <param name="sign">支付宝生成的签名结果</param>
        /// <returns>验证结果</returns>
        public bool Verify(SortedDictionary<string, string> inputPara, string notify_id, string sign)
        {
            //获取返回时的签名验证结果
            bool isSign = GetSignVeryfy(inputPara, sign);
            //获取是否是支付宝服务器发来的请求的验证结果
            string responseTxt = "false";
            if (notify_id != null && notify_id != "") { responseTxt = GetResponseTxt(notify_id); }

            //写日志记录(若要调试,请取消下面两行注释)
            //string sWord = "responseTxt=" + responseTxt + "\n isSign=" + isSign.ToString() + "\n 返回回来的参数:" + GetPreSignStr(inputPara) + "\n ";
            //Core.LogResult(sWord);

            //判断responsetTxt是否为true,isSign是否为true
            //responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
            //isSign不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
            if (responseTxt == "true" && isSign)//验证成功
            {
                return true;
            }
            else//验证失败
            {
                return false;
            }
        }

        /// <summary>
        /// 获取待签名字符串(调试用)
        /// </summary>
        /// <param name="inputPara">通知返回参数数组</param>
        /// <returns>待签名字符串</returns>
        private string GetPreSignStr(SortedDictionary<string, string> inputPara)
        {
            Dictionary<string, string> sPara = new Dictionary<string, string>();

            //过滤空值、sign与sign_type参数
            sPara = AlipayCore.FilterPara(inputPara);

            //获取待签名字符串
            string preSignStr = AlipayCore.CreateLinkString(sPara);

            return preSignStr;
        }

        /// <summary>
        /// 获取返回时的签名验证结果
        /// </summary>
        /// <param name="inputPara">通知返回参数数组</param>
        /// <param name="sign">对比的签名结果</param>
        /// <returns>签名验证结果</returns>
        private bool GetSignVeryfy(SortedDictionary<string, string> inputPara, string sign)
        {
            Dictionary<string, string> sPara = new Dictionary<string, string>();

            //过滤空值、sign与sign_type参数
            sPara = AlipayCore.FilterPara(inputPara);
            
            //获取待签名字符串
            string preSignStr = AlipayCore.CreateLinkString(sPara);

            //获得签名验证结果
            bool isSgin = false;
            if (sign != null && sign != "")
            {
                switch (_sign_type)
                {
                    case "MD5":
                        isSgin = AlipayMD5.Verify(preSignStr, sign, _key, _input_charset);
                        break;
                    default:
                        break;
                }
            }

            return isSgin;
        }

        /// <summary>
        /// 获取是否是支付宝服务器发来的请求的验证结果
        /// </summary>
        /// <param name="notify_id">通知验证ID</param>
        /// <returns>验证结果</returns>
        private string GetResponseTxt(string notify_id)
        {
            string veryfy_url = Https_veryfy_url + "partner=" + _partner + "&notify_id=" + notify_id;

            //获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
            string responseTxt = Get_Http(veryfy_url, 120000);

            return responseTxt;
        }

        /// <summary>
        /// 获取远程服务器ATN结果
        /// </summary>
        /// <param name="strUrl">指定URL路径地址</param>
        /// <param name="timeout">超时时间设置</param>
        /// <returns>服务器ATN结果</returns>
        private string Get_Http(string strUrl, int timeout)
        {
            string strResult;
            try
            {
                HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(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;
        }
    }
}

4:AlipaySubmit类文件:构造支付宝各接口表单HTML文本,获取远程HTTP数据

using System.Web;
using System.Text;
using System.IO;
using System.Net;
using System;
using System.Collections.Generic;
using System.Xml;

namespace CS
{
    /// <summary>
    /// 类名:Submit
    /// 功能:支付宝各接口请求提交类
    /// 详细:构造支付宝各接口表单HTML文本,获取远程HTTP数据
    /// 版本:3.3
    /// 修改日期:2011-07-05
    /// 说明:
    /// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
    /// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考
    /// </summary>
    public class AlipaySubmit
    {
        #region 字段
        //支付宝网关地址(新)
        private static string GATEWAY_NEW = "https://mapi.alipay.com/gateway.do?";
        //商户的私钥
        private static string _key = "";
        //编码格式
        private static string _input_charset = "";
        //签名方式
        private static string _sign_type = "";
        #endregion

        static AlipaySubmit()
        {
            _key = AlipayConfig.key.Trim();
            _input_charset = AlipayConfig.input_charset.Trim().ToLower();
            _sign_type = AlipayConfig.sign_type.Trim().ToUpper();
        }

        /// <summary>
        /// 生成请求时的签名
        /// </summary>
        /// <param name="sPara">请求给支付宝的参数数组</param>
        /// <returns>签名结果</returns>
        private static string BuildRequestMysign(Dictionary<string, string> sPara)
        {
            //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
            string prestr = AlipayCore.CreateLinkString(sPara);

            //把最终的字符串签名,获得签名结果
            string mysign = "";
            switch (_sign_type)
            {
                case "MD5":
                    mysign = AlipayMD5.Sign(prestr, _key, _input_charset);
                    break;
                default:
                    mysign = "";
                    break;
            }

            return mysign;
        }

        /// <summary>
        /// 生成要请求给支付宝的参数数组
        /// </summary>
        /// <param name="sParaTemp">请求前的参数数组</param>
        /// <returns>要请求的参数数组</returns>
        private static Dictionary<string, string> BuildRequestPara(SortedDictionary<string, string> sParaTemp)
        {
            //待签名请求参数数组
            Dictionary<string, string> sPara = new Dictionary<string, string>();
            //签名结果
            string mysign = "";

            //过滤签名参数数组
            sPara = AlipayCore.FilterPara(sParaTemp);

            //获得签名结果
            mysign = BuildRequestMysign(sPara);

            //签名结果与签名方式加入请求提交参数组中
            sPara.Add("sign", mysign);
            sPara.Add("sign_type", _sign_type);

            return sPara;
        }

        /// <summary>
        /// 生成要请求给支付宝的参数数组
        /// </summary>
        /// <param name="sParaTemp">请求前的参数数组</param>
        /// <param name="code">字符编码</param>
        /// <returns>要请求的参数数组字符串</returns>
        private static string BuildRequestParaToString(SortedDictionary<string, string> sParaTemp, Encoding code)
        {
            //待签名请求参数数组
            Dictionary<string, string> sPara = new Dictionary<string, string>();
            sPara = BuildRequestPara(sParaTemp);

            //把参数组中所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对参数值做urlencode
            string strRequestData = AlipayCore.CreateLinkStringUrlencode(sPara, code);

            return strRequestData;
        }

        /// <summary>
        /// 建立请求,以表单HTML形式构造(默认)
        /// </summary>
        /// <param name="sParaTemp">请求参数数组</param>
        /// <param name="strMethod">提交方式。两个值可选:post、get</param>
        /// <param name="strButtonValue">确认按钮显示文字</param>
        /// <returns>提交表单HTML文本</returns>
        public static string BuildRequest(SortedDictionary<string, string> sParaTemp, string strMethod, string strButtonValue)
        {
            Dictionary<string, string> dicPara = new Dictionary<string, string>();
            //获取请求参数数组
            dicPara = BuildRequestPara(sParaTemp);
            StringBuilder sbHtml = new StringBuilder();
            foreach (KeyValuePair<string, string> temp in dicPara)
            {
                sbHtml.Append("<input type='hidden' name='" + temp.Key + "' value='" + temp.Value + "'/>");
            }
            return sbHtml.ToString();
        }



        /// <summary>
        /// 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
        /// 注意:远程解析XML出错,与IIS服务器配置有关
        /// </summary>
        /// <returns>时间戳字符串</returns>
        public static string Query_timestamp()
        {
            string url = GATEWAY_NEW + "service=query_timestamp&partner=" + AlipayConfig.partner + "&_input_charset=" + AlipayConfig.input_charset;
            string encrypt_key = "";

            XmlTextReader Reader = new XmlTextReader(url);
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(Reader);

            encrypt_key = xmlDoc.SelectSingleNode("/alipay/response/timestamp/encrypt_key").InnerText;

            return encrypt_key;
        }
    }
}

5:AlipayBody类文件:这个类是我自己根据项目需要传入的属性写的类,后面作为附加的参数传入接口,支付后返回的接口会全部获取到。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CS
{
    public class AlipayBody
    {
        public int order_id { get; set; }

        public string uname { get; set; }
        public string order_detail { get; set; }

        public string order_name { get; set; }

    }
}

6.AlipayMD5类文件:MD5加密算法,对参数进行加密

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;

namespace CS
{
    /// <summary>
    /// 类名:MD5
    /// 功能:MD5加密
    /// 版本:3.3
    /// 修改日期:2012-07-05
    /// 说明:
    /// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
    /// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
    /// </summary>
    public sealed class AlipayMD5
    {
        public AlipayMD5()
        {
            //
            // TODO: 在此处添加构造函数逻辑
            //
        }

        /// <summary>
        /// 签名字符串
        /// </summary>
        /// <param name="prestr">需要签名的字符串</param>
        /// <param name="key">密钥</param>
        /// <param name="_input_charset">编码格式</param>
        /// <returns>签名结果</returns>
        public static string Sign(string prestr, string key, string _input_charset)
        {
            StringBuilder sb = new StringBuilder(32);

            prestr = prestr + key;

            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] t = md5.ComputeHash(Encoding.GetEncoding(_input_charset).GetBytes(prestr));
            for (int i = 0; i < t.Length; i++)
            {
                sb.Append(t[i].ToString("x").PadLeft(2, '0'));
            }

            return sb.ToString();
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="prestr">需要签名的字符串</param>
        /// <param name="sign">签名结果</param>
        /// <param name="key">密钥</param>
        /// <param name="_input_charset">编码格式</param>
        /// <returns>验证结果</returns>
        public static bool Verify(string prestr, string sign, string key, string _input_charset)
        {
            string mysign = Sign(prestr, key, _input_charset);
            if (mysign == sign)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}

7.AlipayAskHtml类文件:生成支付宝请求html

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CS
{
    public class AlipayAskHtml
    {
        /// <summary>
        /// 生成支付宝请求html
        /// </summary>
        /// <param name="out_trade_no">商户订单号,商户网站订单系统中唯一订单号,必填</param>
        /// <param name="subject">订单名称,必填</param>
        /// <param name="total_fee">付款金额,必填</param>
        /// <param name="body">商品描述,可空</param>
        /// <returns></returns>
        public string GetAlipayPayAskHtml(string out_trade_no, string subject, string total_fee, string body)
        {
            //把请求参数打包成数组
            SortedDictionary<string, string> sParaTemp = new SortedDictionary<string, string>();
            sParaTemp.Add("service", AlipayConfig.service);
            sParaTemp.Add("partner", AlipayConfig.partner);
            sParaTemp.Add("seller_id", AlipayConfig.seller_id);
            sParaTemp.Add("_input_charset", AlipayConfig.input_charset.ToLower());
            sParaTemp.Add("payment_type", AlipayConfig.payment_type);
            sParaTemp.Add("notify_url", AlipayConfig.notify_url);
            sParaTemp.Add("return_url", AlipayConfig.return_url);
            sParaTemp.Add("anti_phishing_key", AlipayConfig.anti_phishing_key);
            sParaTemp.Add("exter_invoke_ip", AlipayConfig.exter_invoke_ip);
            sParaTemp.Add("out_trade_no", out_trade_no);
            sParaTemp.Add("subject", subject);
            sParaTemp.Add("total_fee", total_fee);
            sParaTemp.Add("body", body);
            //其他业务参数根据在线开发文档,添加参数.文档地址:https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.O9yorI&treeId=62&articleId=103740&docType=1
            //如sParaTemp.Add("参数名","参数值");
            //建立请求
            string AlipayHtmlText = AlipaySubmit.BuildRequest(sParaTemp, "get", "确认");
            return AlipayHtmlText;
        }
    }
}

8.调用请求支付宝支付方法:

返回的aliPayStr返回的数据是Json格式:

 <input type='hidden' name='_input_charset' value='utf-8'/>
 <input type='hidden' name='body' value='{"order_id":121,"uname":"test2","order_detail":"","order_name":"体育健康活动材料包2.0(6项2018821135433GiyNdpdbT6"}'/>
 <input type='hidden' name='notify_url' value='http://*****.com/aliPay/notify_url.aspx'/>
 <input type='hidden' name='out_trade_no' value='2018821135433GiyNdpdbT6'/>
 <input type='hidden' name='partner' value='20880011334***'/>
 <input type='hidden' name='payment_type' value='1'/>
 <input type='hidden' name='return_url' value='http://garden.yphtoy.com/aliPay/return_url.aspx'/>
 <input type='hidden' name='seller_id' value='20880011*****/>
 <input type='hidden' name='service' value='create_direct_pay_by_user'/>
 <input type='hidden' name='subject' value='体育健康活动材料包2.0(6项2018821135433GiyNdpdbT6'/>
 <input type='hidden' name='total_fee' value='22800.00'/>
 <input type='hidden' name='sign' value='bd1b64ccca74f9cbc0e2c8782131adb3'/>
 <input type='hidden' name='sign_type' value='MD5'/>
 /// <summary>
    /// 
    /// </summary>
    /// <param name="pay_type_id">支付类型</param>
    /// <param name="order_Id">订单id</param>
    /// <param name="order_flow_num">订单流水号</param>
    /// <param name="order_memo_out">订单备注</param>
    /// <param name="order_subject_out">订单名称</param>
    /// <param name="order_amount_out">订单总金额</param>
    /// <param name="errorMethod">方法名</param>
    /// <returns></returns>
    public string GetUserOrderDetailByPay(string pay_type_id, string order_Id, string order_flow_num, string order_memo_out, string order_subject_out, string order_amount_out, string errorMethod)
    {
        AlipayBody body = new AlipayBody();
        ExcuteResult result = new ExcuteResult();
        //支付宝
        if (pay_type_id == "0")
        {
            body.order_id = order_Id.toString(0);
            body.uname = Config.GardenUser == null ? "" : Config.GardenUser.uname;
            body.order_detail = order_memo_out;
            body.order_name = order_subject_out;
            string aliPayStr = new AlipayAskHtml().GetAlipayPayAskHtml(order_flow_num, order_subject_out, order_amount_out, JsonConvert.SerializeObject(body));
            if (aliPayStr.IsNullOrEmpty())
            {
                ZH.SaveErr(new ErrorLog()
                {
                    ErrorId = order_flow_num,
                    ErrorUser = Config.GardenUser == null ? "" : Config.GardenUser.uname,
                    ErrorTime = DateTime.Now,
                    ErrorClass = "Garden.cs",
                    ErrorMethod = errorMethod,
                    ErrorMsg = "aliPayStr为空!支付宝返回支付地址失败!"
                }.toJson());
                result.Result = false;
                result.Msg = "aliPayStr为空!支付宝返回支付地址失败!";
                return JsonConvert.SerializeObject(result);
            }
            result.Result = true;
            result.Msg = aliPayStr;
        }
    
        return JsonConvert.SerializeObject(result);
           
    }

二.前台代码部分:

HTML页面:

    <%-- 支付 --%>
    <form  id="alipaysubmit" target="_blank" name="alipaysubmit" action="https://mapi.alipay.com/gateway.do?_input_charset=utf-8" method="get">
        <input type="submit" id="submitje" style="display: none;" />
        <div id="inputs">

        </div>
    </form>

Js代码部分:

   //立即支付
    $(".allOrderTable").on("click", ".payNow", function () {
        var order_id = $(this).parent().parent().attr("order_id");
        var pay_type_id = $(this).parent().parent().attr("pay_type_id");
        $.ajax_({
            method: "GetUserOrderDetailByPay",
            data: { id: order_id },
            success: function (e) {
                var data = JSON.parse(e.d);
                if (data.Result == true) {

                    //这里非常重要,将后台的Html表单控件绑定到div中,然后表单提交,
                    //就会跳转到支付宝支付页面。
                    $("#inputs").html(data.Msg);
                    if (pay_type_id == 0) {
                        //支付宝支付
                        $("#submitje").click();  //点击提交表单
                        console.log("suc");
                    } else {
                        //微信支付
                        
                    }

                } else {
                    var msg = "";
                    if (pay_type_id == 0) {
                        msg = data.Msg;
                    }
                    else {
                        msg = JSON.parse(data.Msg).return_msg;
                    }
                    $.DialogByZ.Alert({
                        Title: "提示信息", Content: msg, BtnL: "确定", FunL: function () {
                            $.DialogByZ.Close();
                            location.href = "AllOrder.aspx";
                        }
                    });
                }
            }
        })
    })

展示效果:

猜你喜欢

转载自blog.csdn.net/liuchang19950703/article/details/81905036
今日推荐