PayPal支付接入

来源:http://www.cnblogs.com/eggqing/archive/2016/04/25/5429983.html
-Advertisement-
Play Games

在騷擾了PayPal的技術支持好幾天之後終於成功對接了PayPal支付,非常感謝PayPal的技術支持人員,沒有她估計一周都搞不定。記錄一下這個過程。 接到這個任務聯繫了PayPal的技術之後,第一件事就是向她要了一些文檔。PayPal提供了一個demo商店https://demo.paypal.c ...



在騷擾了PayPal的技術支持好幾天之後終於成功對接了PayPal支付,非常感謝PayPal的技術支持人員,沒有她估計一周都搞不定。記錄一下這個過程。

接到這個任務聯繫了PayPal的技術之後,第一件事就是向她要了一些文檔。PayPal提供了一個demo商店https://demo.paypal.com/c2/demo/navigation?merchant=bigbox&page=shoppingCart&locale.x=zh_XC&token=EC-8F899625FB177521V

,首先我在上面體驗了一把PayPal支付的整個流程,登錄sandbox賬號然後支付就行了,可以看下麵的截圖感受一下,

 

 

sandbox賬號是你註冊了企業賬號之後PayPal送給你的兩個測試用賬號,你可以在sandbox環境中測試你的代碼,當然你也可以自己註冊sandbox賬號,當商務部給我一個企業賬號密碼時,我登錄https://developer.paypal.com/developer/accounts?event=linkAccountAssociated

可以看到裡面的sandbox賬戶,我選擇新建一個自己的sandbox商家賬戶,與live環境同樣且必須要做的是申請簽名:https://www.sandbox.paypal.com/webapps/customerprofile/summary.view

(切記!!!sandbox環境用live環境的簽名會報"security header is not valid",這是sandbox的簽名,同樣的,live環境只需要功能變數名稱中去掉

sandbox即可找到),如下圖

PayPal的API有提供兩種調用方式,NVP和SOAP,我選擇了前者。支持方式是IPN,一般都是選擇IPN,因為我們開發基本上都要根據支付平臺的結果處理一下自己的業務,在看了IPN這個文檔https://www.paypal-biz.com/product/pdf/PayPal_IPN&PDT_Guide_V1.0.pdf之後,大致瞭解了和PayPal的交互流程,文檔中的notify_url是PayPal在你調用DoEC後回調你的鏈接,PayPal會在請求你鏈接時帶上一些訂單的參數,詳請點擊

https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/

做了這些準備工作之後我們可以開始寫代碼了。

此處應當插入個時序圖的-_-!!

調用API都會用到的公共參數是:"USER=""PWD=""SIGNATURE=""VERSION=",後面不再贅述

下訂單調用PayPal的SetExpressCheckout方法,可以參考這個已經過驗證的示例(密碼簽名記得用自己申請的哦_):

附上你們也許用得著的代碼:

Map<String, String> nvpMap = PayPalUtil.setExpressCheckout(params);
if (nvpMap != null && nvpMap.get("ACK") != null) {
String strAck = nvpMap.get("ACK").toUpperCase();
if (strAck.equals("SUCCESS")
|| strAck.equals("SUCCESSWITHWARNING")) {

String checkoutUrl = PayPalUtil.checkoutUrl;
String token = checkoutUrl, nvpMap.get("TOKEN");//下單成功之後可以保存此token以做後續調用API之用

//do something

} else {
String ErrorCode = nvpMap.get("L_ERRORCODE0");
String ErrorShortMsg = nvpMap.get("L_SHORTMESSAGE0");
String ErrorLongMsg = nvpMap.get("L_LONGMESSAGE0");
String ErrorSeverityCode = nvpMap.get("L_SEVERITYCODE0");
String errorString = "SetExpressCheckout API call failed. "
+ "Detailed Error Message: " + ErrorLongMsg
+ "Short Error Message: " + ErrorShortMsg
+ "Error Code: " + ErrorCode
+ "Error Severity Code: " + ErrorSeverityCode;
log.error(errorString);

}
}

 

具體的請求參數以及響應說明在這裡:https://developer.paypal.com/webapps/developer/docs/classic/api/merchant/SetExpressCheckout_API_Operation_NVP/

下單成功拿到與此訂單相關的token之後,用戶點擊continue付款之後PayPal會請求你在setExpressCheckout中傳給PayPal的RETURNURL,PayPal帶來的請求參數中只有兩個參數,

一個token,一個payerID這兩個參數都是在調用最後一個DoExpressCheckout API的時候要傳的,PayPal的請求可能如下示例:

http://XXX.com/paypal?token=EC-0B0244963D237432J&PayerID=93JGVG4CSVCN4 ,PayerID為買家的account ID.因此,你必須提供一個處理類來處理PayPal的請求,接到PayPal請求之後,接下來你要做的是調用API GetExpressCheckoutDetails

需要帶上兩個參數:METHOD=GetExpressCheckoutDetails&TOKEN=DJFJSLDFJS ,這個API並不是必須調用,建議調用來獲取訂單信息和訂單狀態,比如金額等做風控校驗。響應碼詳情請參考:
https://developer.paypal.com/docs/classic/api/merchant/GetExpressCheckoutDetails_API_Operation_NVP/

來到這裡,離成功只差一步了,那就是在上面確認了訂單無誤之後調用API DoExpressCheckoutPayment告訴PayPal這個交易沒錯,你可以扣錢了~~~最後你可以再重定向到自己的商戶頁面。以下參數為必須:
parasMap.put("METHOD", "DoExpressCheckoutPayment");
parasMap.put("TOKEN", token);
parasMap.put("PAYERID", payerId);
parasMap.put("PAYMENTREQUEST_0_PAYMENTACTION", "Sale");//sale是立即到賬,order是預授權,一般都是sale
parasMap.put("PAYMENTREQUEST_0_AMT", amount);
parasMap.put("PAYMENTREQUEST_0_NOTIFYURL", notify_url);//這個notify_url是成功調用DoExpressCheckoutPayment後PayPal最後請求你的處理器,你可以做一些風險控制。裡面同樣會傳很多的訂單數據給你。


DoExpressCheckoutPayment的請求與相應:
https://developer.paypal.com/webapps/developer/docs/classic/api/merchant/DoExpressCheckoutPayment_API_Operation_NVP/

PayPal在最後請求你的notify_url中所帶來的參數如下:
https://developer.paypal.com/webapps/developer/docs/classic/ipn/integration-guide/IPNandPDTVariables/


另外的兩個用於查詢訂單的API你也許也會用得到:

TransactionSearch API Operation (NVP) : https://developer.paypal.com/docs/classic/api/merchant/TransactionSearch_API_Operation_NVP/

GetTransactionDetails API Operation (NVP) : https://developer.paypal.com/docs/classic/api/merchant/GetTransactionDetails_API_Operation_NVP/

然而有一個問題,所需的參數txn_id是PayPal在notify_url請求時才帶來的,這可是最後一個交互了,萬一丟了這個訂單豈不是再也查不到了?別急,看本文最後的說明。

PayPal錯誤碼參考:
https://developer.paypal.com/docs/classic/api/errorcodes/


有幾點最後但卻非常重要的需要說明:

1.用心的同學估計已經發現了,以上所述與IPN的文檔少了一步,那就是IPN文檔"1.3 通知確認- 給PayPal的https回撥",這步在我咨詢了PayPal的技術支持後我直接省略了,正如文檔中所說,假如你滿足如下條件,建議保留此步:

您的網站是放在共用伺服器上的;您未在您的 Web 伺服器上啟用 SSL;

2.若是你丟失了PayPal的notify_url請求,你可以根據TransactionSearch這個API去查某個訂單詳情,有一個INVNUM的參數,如果你在SetExpressCheckOut時傳過去了,PayPal會幫你保存在訂單中,你可以用此參數獲得某一個訂單,因此這個參數你在SetEC

的時候便可以傳給PayPal,值一般取自己這邊的訂單號。這樣即使你最後收不到notify_url你後續也可以根據你自己的訂單號去獲取訂單。這裡也有一個問題需要切記,這個API中的STARTDATE必須要是GMT時間,轉換代碼如下可以參考:

// Must be a valid date, in UTC/GMT format; for example,
// 2013-08-24T05:38:48Z.
// 將北京時間轉為GMT時間,此處直接減一天好了,雖然只是相差8個小時
SimpleDateFormat pSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
DateFormat fSdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
fSdf.setTimeZone(TimeZone.getTimeZone("GMT"));
try {
Calendar temp = Calendar.getInstance();
temp.setTime(pSdf.parse(startdate));
temp.add(Calendar.DAY_OF_YEAR, -1);
startdate = fSdf.format(temp.getTime());
} catch (ParseException e1) {
e1.printStackTrace();
log.error("時間轉換失敗,startdate為:" + startdate);
return null;
}

 

3.若在你部署了本地環境之後,測試時PayPal無法請求到你的區域網,你可以安裝localtunnel,它可以幫助你
http://stackoverflow.com/questions/11469636/paypal-sandbox-test-tool-ipn-simulator-in-localhost
https://localtunnel.me/

4.若是你的代碼無法請求到PayPal的API,那很有可能你的通信協議不是TLSv1.2,PayPal會在2016年六月底全面啟用TLSv1.2,這是一份聲明:https://github.com/paypal/TLS-update

解決辦法有兩個:

一,配置你的伺服器支持TLSv1.2,jdk1.7是有的,但並未顯示支持,你需要配置jdk使之顯示支持TLSv1.2;你可以參考
http://stackoverflow.com/questions/34963083/paypal-sandbox-api-javax-net-ssl-sslhandshakeexception-received-fatal-alert-h
http://stackoverflow.com/questions/9749339/does-tomcat-supports-tls-v1-2


二,升級至jdk8,預設支持,直接可用。

5.若是你的代碼報"peer not authenticated"這個錯誤,說明你的伺服器證書不受信任。

解決辦法:增加如下方法,

HttpClient httpclient = new DefaultHttpClient();

httpclient = wrapClient(httpclient);

/**
* 獲取可信任https鏈接,以避免不受信任證書出現peer not authenticated異常
*
* @param base
* @return
*/
public static HttpClient wrapClient(HttpClient base) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {

@Override
public void checkClientTrusted(X509Certificate[] arg0,
String arg1) throws CertificateException {
// TODO Auto-generated method stub

}

@Override
public void checkServerTrusted(X509Certificate[] arg0,
String arg1) throws CertificateException {
// TODO Auto-generated method stub

}

@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = base.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", ssf, 443));

return new DefaultHttpClient(ccm, base.getParams());
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 如果在應用中,如果想要給app 添加模糊濾鏡,可能第一想到的是第三方類庫,比如 Win2d、lumia Imaging SDK 、WriteableBitmapEx,不可否認,這些類庫功能強大,效果也挺多的。不足就是增加了生成包尺寸,由於增加了相應 dll 的引用,在 app運行時也會增加記憶體占用。 ...
  • 公司里每個程式員在命名空間的排序和註釋上都有很多的不同。 雜亂的命名空間: 有序的命名空間: 為了方便管理代碼,這裡我製作了一個批量處理.cs文件中命名空間排序及註釋的工具。 代碼: 我是怎麼判斷更新的呢?答案是判斷cs文件中是否有“// System namespaces”這句話,如果有的話就不需 ...
  • Server Error in '/' Application. The system cannot find the file specified Description: An unhandled exception occurred during the execution of the cu ...
  • Struts2.0已經成為了一個高度成熟的框架,不管是穩定性還是可靠性都得到了廣泛的證明。 擁有豐富的開發人群,幾乎已經成為了事實上的工業標準。因此,學習MVC框架,struts2.0幾乎是必須熟悉的。 本課程從基本的struts2.0使用開始,深入原理講解,授人以漁!同時,將工作中容易出現的細節問 ...
  • 作者:白狼 出處:http://www.manks.top/article/yii2_captcha本文版權歸作者,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。 本來以為yii2框架驗證碼這塊很全面,嘗試百度google了一下,大多數教程寫 ...
  • 一、 Comparable<T>: Comparable是類內部的比較器,用於創建類的時候實現此介面,同時實現比較方法;對於不能修改源碼的類則無法應用此方式進行比較排序等。 源碼為: 1 public interface Comparable<T> { 2 public int compareTo( ...
  • 這是一個NB的安全認證機制。 1、這是一個安全認證機制 2、可以防止黑客截獲到客戶端發送的請求消息,避免了黑客冒充客戶端向伺服器發送操作的請求。 原理與步驟: 1、客戶端與伺服器端都會放著一份驗證用的token欄位,這欄位無論通過什麼方式前提是不能被黑客提前拿到。 2、客戶端在本地把時間戳和toke ...
  • 亂碼 上節說到亂碼出現的主要原因,即在進行編碼轉換的時候,如果將原來的編碼識別錯了,併進行了轉換,就會發生亂碼,而且這時候無論怎麼切換查看編碼的方式,都是不行的。 我們來看一個這種錯誤轉換後的亂碼,還是用上節的例子,二進位是(16進位表示):C3 80 C3 8F C3 82 C3 AD,無論按哪種 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...