說明
最近用到了 Paypal 支付功能,英語一般般的我也不得不硬著頭皮踩一踩這樣的坑。經(jīng)過近乎半個月的作,終于實現(xiàn)了簡單的支付功能,那么首先就說說使用 Paypal 必定要知道的幾點(當前日期 2018年08月07日):
1. 你應(yīng)該知道 Paypal 支付功能是支持銀聯(lián)卡的,但是不支持中國買家賬號支付給中國賣家賬號
2. Paypal 接口有兩套,切記,產(chǎn)品環(huán)境和 sandbox 測試環(huán)境不同
3. 測試賬號同樣不能使用中國賬號給中國賬號付款
4. 如果你僅僅想具有固定金額的支付按鈕,用你的 Paypal 商家賬號登錄官網(wǎng),配置頁里面完全可以配置出固定的支付按鈕,然后 Copy 對應(yīng)的 Html 到你的頁面就 OK 了,也就沒有必要通過更復(fù)雜的方式去支付了
5. 如果你必須動態(tài)價格和商品信息、或者你要學習基本的 Paypal 接口的話,那么就請靜靜的往下看吧
6. 真實環(huán)境支付 Paypal 每一筆都需要收取商家賬號手續(xù)費的,并且手續(xù)費不低,如果你用真實環(huán)境測試,那么一定要記得每一筆都申請退款吧,退款很方便,商家后臺就能直接發(fā)起,退款幾乎是實時的。
Paypal 費用說明:https://www.paypal.com/businesswallet/fees/paypal-fees
?相關(guān)資料
Paypal 官方地址:https://www.paypal.com/
Paypal 官方測試地址:https://www.sandbox.paypal.com
Paypal 開發(fā)者中心:https://developer.paypal.com/
Paypal API:?https://api.paypal.com
Paypal sandbox API:?https://api.sandbox.paypal.com
Paypal Checkout JS 支付模式
模式圖片:
?
模式說明:
Checkout JS 模式是一種前端實現(xiàn),使用官方提供的 Checkout.js SDK 實現(xiàn)支付,不需要自己寫直接調(diào)用接口的代碼,相對而言也挺簡單,但是如果你想檢測支付是否成功,你應(yīng)當通過調(diào)用接口的方式驗證了。
支付部分代碼:
<p id="paypal-button"></p>
<script src="https://www.paypalobjects.com/api/checkout.js"></script>
<script type="text/javascript"> paypal.Button.render({ env: 'production', // production or sandbox 表示產(chǎn)品環(huán)境還是測試環(huán)境 client: { production: '', // 產(chǎn)品環(huán)境,值為字符串,配置實際商家號的 ClientId // sandbox: '', // 測試環(huán)境,值為字符串,配置商家測試號的 ClientId }, style: { size: 'medium', color: 'black', shape: 'pill', label: 'paypal', tagline: 'false', fundingicons: 'true' }, commit: true, payment: function (data, actions) { return actions.payment.create({ transactions: [ { amount: { total: "0.01", currency: "USD" }, description: "測試商品描述", custom: "X00002" } ], redirect_urls: { return_url: 'http://localhost:4478/Success.aspx?type=js', cancel_url: 'http://localhost:4478/Cancel.aspx' } }); }, onAuthorize: function (data, actions) { return actions.payment.execute() .then(function () { actions.redirect(); }); }, onCancel: function (data, actions) { actions.redirect(); } }, '#paypal-button'); </script>
如果你需要在支付跳轉(zhuǎn)的成功頁再次驗證一下是否支付成功,你需要自己調(diào)用官方提供的 RESTful API,參見下文的 RESTful API 支付模式
RESTful API 支付模式
說明
接口的方式很常見,和支付寶的接口類似,只是使用了 RESTful API 的模式,采用了 Basic Auth 的加密方式。使用接口的模式很常規(guī),我們在頁面點擊按鈕調(diào)用支付接口,彈出支付頁,支付成功跳轉(zhuǎn)到成功頁面,成功頁面再調(diào)用確認支付接口確認結(jié)果。
支付接口調(diào)用:
using System; using System.Text; using System.Web.Script.Serialization; using cn.lovelong.Paypal.Config; using cn.lovelong.Paypal.Enums; using cn.lovelong.Paypal.Model; namespace cn.lovelong.Paypal.Paypal { /// <summary> /// CreatePayment 的摘要說明 /// </summary> public class CreatePayment { public CreatePayment() { } public PaymentResult Pay(string json) { var jsonResult = HttpHelper.PostJson( UrlConfig.CreatePaymentUrl, AccountConfig.ClientId, AccountConfig.Secret, json, Encoding.UTF8); var result = new JavaScriptSerializer().Deserialize<PaymentResult>(jsonResult); return result; } public PaymentResult Pay(PaymentParam param) { var json = GetPayParams(param); return Pay(json); } public string GetPayParams(PaymentParam param) { var total = param.Total.ToString("N"); var currency = Enum.GetName(typeof (PaypalCurrency), param.Currency); var payParams = new { intent = "sale", redirect_urls = new { return_url = param.ReturnUrl, cancel_url = param.CancelUrl, }, payer = new { payment_method = "paypal" }, transactions = new dynamic[] { new { amount = new { total = total, currency = currency }, description = param.Description, custom = param.Code, item_list = new { items = new dynamic[] { new { name = param.Name, //description = param.Name, quantity = "1", price = total, //tax = "0.01", //sku = "1", currency = currency } } } } } }; var json = new JavaScriptSerializer().Serialize(payParams); return json; } public string GetFullPayParams(decimal total, PaypalCurrency currency, string returnUrl, string cancelUrl) { var payParams = new { intent = "sale", redirect_urls = new { return_url = returnUrl, cancel_url = cancelUrl, }, payer = new { payment_method = "paypal" }, transactions = new dynamic[] { new { amount = new { total = total.ToString("N"), currency = Enum.GetName(typeof(PaypalCurrency),currency), details = new { subtotal = "30.00", tax = "0.07", shipping = "0.03", handling_fee = "1.00", shipping_discount = "-1.00", insurance = "0.01" } }, description = "", custom = "EBAY_EMS_90048630024435", invoice_number = "48787589673", payment_options = new { allowed_payment_method = "INSTANT_FUNDING_SOURCE" }, soft_descriptor = "ECHI5786786", item_list = new { items = new dynamic[] { new { name = "hat", description = "Brown hat.", quantity = "5", price = "3", tax = "0.01", sku = "1", currency = "USD" } }, shipping_address = new { recipient_name = "Brian Robinson", line1 = "4th Floor", line2 = "Unit #34", city = "San Jose", country_code = "US", postal_code = "95131", phone = "011862212345678", state = "CA" }, } } } }; var json = new JavaScriptSerializer().Serialize(payParams); return json; } } }
確認支付接口:
using System.Text; using System.Web.Script.Serialization; using cn.lovelong.Paypal.Config; using cn.lovelong.Paypal.Model; namespace cn.lovelong.Paypal.Paypal { /// <summary> /// Approved 的摘要說明 /// </summary> public class Approved { public PaymentResult DoJson(string paymentId, dynamic json) { var jsonResult = HttpHelper.PostJson(string.Format(UrlConfig.ApprovedUrl, paymentId), AccountConfig.ClientId, AccountConfig.Secret, json, Encoding.UTF8); var result = new JavaScriptSerializer().Deserialize<PaymentResult>(jsonResult); return result; } public PaymentResult Do(string paymentId, string payerId) { var json = GetPayParams(payerId); return DoJson(paymentId, json); } public string GetPayParams(string payerId) { var payParams = new { payer_id = payerId }; var json = new JavaScriptSerializer().Serialize(payParams); return json; } } }
查詢支付結(jié)果接口調(diào)用:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Script.Serialization; using cn.lovelong.Paypal.Config; using cn.lovelong.Paypal.Model; namespace cn.lovelong.Paypal.Paypal { public class ShowPaymentDetails { public PaymentResult Do(string paymentId) { var json = HttpHelper.Get( string.Format(UrlConfig.ShowPaymentDetailsUrl, paymentId), AccountConfig.ClientId, AccountConfig.Secret, Encoding.UTF8); var result = new JavaScriptSerializer().Deserialize<PaymentResult>(json); return result; } } }
最容易出問題的反而是通用類 HttpHelper:
using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Security.Policy; using System.Text; using System.Threading.Tasks; namespace cn.lovelong.Paypal { public class HttpHelper { public static string PostForm(string url, string userName, string password, Dictionary<string,object> dic, Encoding encoding) { var param = string.Empty; foreach (var o in dic) { if (string.IsNullOrEmpty(param)) param += o.Key + "=" + o.Value; else param += "&" + o.Key + "=" + o.Value; } byte[] byteArray = encoding.GetBytes(param); //處理HttpWebRequest訪問https有安全證書的問題( 請求被中止: 未能創(chuàng)建 SSL/TLS 安全通道。) ServicePointManager.ServerCertificateValidationCallback += (s, cert, chain, sslPolicyErrors) => true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(encoding.GetBytes(userName + ":" + password))); request.PreAuthenticate = true; request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = byteArray.Length; //寫入?yún)?shù) Stream newStream = request.GetRequestStream(); newStream.Write(byteArray, 0, byteArray.Length); newStream.Close(); using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (var stream = response.GetResponseStream()) { if(stream != null) using (StreamReader sr = new StreamReader(stream, Encoding.UTF8)) { return sr.ReadToEnd(); } } } return string.Empty; } public static string PostJson(string url, string userName, string password, string json, Encoding encoding) { byte[] byteArray = encoding.GetBytes(json); //處理HttpWebRequest訪問https有安全證書的問題( 請求被中止: 未能創(chuàng)建 SSL/TLS 安全通道。) ServicePointManager.ServerCertificateValidationCallback += (s, cert, chain, sslPolicyErrors) => true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url); request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(encoding.GetBytes(userName + ":" + password))); request.PreAuthenticate = true; request.Method = "POST"; request.Headers.Add("Cache-Control", "no-cache"); request.ContentType = "application/json"; request.ContentLength = byteArray.Length; //寫入?yún)?shù) Stream newStream = request.GetRequestStream(); newStream.Write(byteArray, 0, byteArray.Length); newStream.Close(); using (HttpWebResponse response = (HttpWebResponse) request.GetResponse()) { using (var stream = response.GetResponseStream()) { if (stream != null) using (StreamReader sr = new StreamReader(stream, Encoding.UTF8)) { return sr.ReadToEnd(); } } } return string.Empty; } public static string Get(string url, string userName, string password, Encoding encoding) { //處理HttpWebRequest訪問https有安全證書的問題( 請求被中止: 未能創(chuàng)建 SSL/TLS 安全通道。) ServicePointManager.ServerCertificateValidationCallback += (s, cert, chain, sslPolicyErrors) => true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(encoding.GetBytes(userName + ":" + password))); request.PreAuthenticate = true; request.Method = "GET"; using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { using (var stream = response.GetResponseStream()) { if (stream != null) using (StreamReader sr = new StreamReader(stream, Encoding.UTF8)) { return sr.ReadToEnd(); } } } return string.Empty; } } }
主要的功能都已經(jīng)實現(xiàn)了!看看演示 Demo 吧!
1. 支付頁面
2. Checkout JS 方式(如果你的頁面點擊登錄之后一直在第二個頁面轉(zhuǎn)圈的話,那只能說明你的登錄賬號不能支付你的商家賬號,或者你的賬號如果登錄之后顯示添加銀行卡的提示,說明你的商家賬號和你的賬號都是中國賬號,那你只能添加多幣種卡支付,不能用銀聯(lián)支付了):
付款就好了!
3. 接口方式我就沒有使用彈出頁面了,最簡單的方式(接口會直接在調(diào)用接口的頁面觸發(fā)支付跳轉(zhuǎn)),點擊接口支付
我就不支付了,我用的商家賬號是自己的新加坡的賬號, 按照今天的匯率 $0.01 = ¥0.068,你至少需要支付 0.07 元才能完成支付,而文章開頭也說了,商家需要付稅,也就是說你支付的 0.07 都會變成給 Paypal 的稅,商家一分錢也拿不到,也就是說,你至少支付 3.5元人民幣($0.51 = ¥3.481)商家才能得到微額的款項。
下面給出 Demo 源碼,源碼中配置的商家號是我自己的,請自行修改,為了方便大家沒有商家賬號的朋友做測試我就不刪除了,朋友們也不要真的支付測試,你的測試只會讓 Paypal 賺錢而已!
我的開發(fā)環(huán)境是 VS2015 + C# 6.0 + JS ,代碼僅供參考,請自行修改擴展學習使用!
相關(guān)推薦:
調(diào)用支付寶PHP接口API實現(xiàn)在線即時支付功能
.Net實現(xiàn)微信JS-SDK分享功能代碼展示-C#.Net教程
The above is the detailed content of C# .NET/JS implementation of Paypal payment function. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

TheyieldkeywordinC#simplifiesiteratorcreationbyautomaticallygeneratingastatemachinethatenableslazyevaluation.1.Itallowsreturningitemsoneatatimeusingyieldreturn,pausingexecutionbetweeneachitem,whichisidealforlargeordynamicsequences.2.yieldbreakcanbeus

The role of IDisposable and using in C# is to efficiently and deterministically manage unmanaged resources. 1. IDisposable provides Dispose() method, so that the class can clearly define how to release unmanaged resources; 2. The using statement ensures that Dispose() is automatically called when the object is out of scope, simplifying resource management and avoiding leakage; 3. When using it, please note that the object must implement IDisposable, can declare multiple objects, and should always use using for types such as StreamReader; 4. Common best practices include not relying on destructors to clean up, correctly handling nested objects, and implementing the Dispose(bool) pattern.

DependencyInjection(DI)inC#isadesignpatternthatenhancesmodularity,testability,andmaintainabilitybyallowingclassestoreceivedependenciesexternally.1.DIpromotesloosecouplingbydecouplingobjectcreationfromusage.2.Itsimplifiestestingthroughmockobjectinject

LambdaexpressionsandLINQsimplifydatamanipulationinC#byenablingconcise,readable,andefficientcode.1.Lambdaexpressionsallowinlinefunctiondefinitions,makingiteasiertopasslogicasargumentsforfiltering,transforming,sorting,andaggregatingdatadirectlywithinme

Nullablereferencetypes(NRTs)inC#8 helpcatchNullReferenceExceptionerrorsatcompiletimebymakingreferencetypesnon-nullablebydefault,requiringexplicitdeclarationfornullability.NRTsmustbeenabledeitherinthe.csprojfilewithenableoratthetopofa.csfileusing#null

Span and Memory improve C# performance by reducing memory allocation. 1. Span avoids array copying and provides light references to existing memory, which is suitable for parsing binary protocols, string operations and high-performance buffer management; 2. Memory supports passing memory slices across asynchronous methods, which is suitable for scenarios where more flexible life cycles are required; 3. Both reduce GC pressure, optimize performance by reusing buffers and avoiding temporary copying; 4. Span is limited to use on the stack and cannot be stored in classes or used in asynchronous methods. Be careful to avoid reassignment operations such as calling.ToArray().

Four common "anti-pattern" problems in C# development need to be avoided. First, the unreasonable use of async/await leads to deadlocks or performance degradation. We should adhere to the principle of full asynchronousness, configure ConfigureAwait(false) and standardize naming; second, excessive dependence on var affects readability, and explicitly declare and unify team specifications when the type is unclear; third, the incorrect use of Dispose and resource management causes leakage, and the use statement should be used correctly and the IDisposable standard mode should be implemented; fourth, the abuse of static classes or singletons causes testing difficulties, and priority should be given to dependency injection, statelessness, or the life cycle managed by containers. Avoiding these misunderstandings can significantly improve code quality and maintenance.

SOLID principle is five design principles to improve code maintainability and scalability in object-oriented programming. They are: 1. The single responsibility principle (SRP) requires that the class only assumes one responsibility, such as separating report generation and email sending; 2. The opening and closing principle (OCP) emphasizes that the extension is supported through interfaces or abstract classes without modifying the original code, such as using the IShape interface to realize area calculation of different graphics; 3. The Richter replacement principle (LSP) requires that the subclass can replace the parent class without destroying logic, such as Square should not mistakenly inherit Rectangle, resulting in abnormal behavior; 4. The interface isolation principle (ISP) advocates the definition of fine-grained interfaces, such as split printing and scanning functions to avoid redundant dependencies; 5. The dependency inversion principle (DIP) advocates the
