paypal支付 paypal网站付款标准版问题解决

Posted RunningFan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了paypal支付 paypal网站付款标准版问题解决相关的知识,希望对你有一定的参考价值。

最近公司要集成paypal支付,由于我们有自己的网站,所以选择了最简单的网站标准付款方式(IPN及时付款)。中间遇到了很多大小问题,现在终于解决了,还是靠查阅大家的分享,花点时间写个小结。

1、注册账号

首先,paypal官网https://www.paypal.com,首先要注册一个企业账号。
或者去开发者平台注册一个开发者账号 https://developer.paypal.com/developer/applications/

2、添加支付按钮

网站标准版支付支付按钮添加详细的介绍,请看网址
https://developer.paypal.com/docs/classic/paypal-payments-standard/integration-guide/buynow_buttons/
并且下面有前端页面的支付代码,由于我是后端开发者,所以我把表单提交复制到html文件中打开即可跳到支付页面。
我们网站需要实现paypal购买虚拟币的功能,所以商品信息比较简单,只需要传入价格,我用到的立即购买表单如下:


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gbk" />
</head>
<!-- paypal沙盒支付测试地址 -->
<form id="pay_form" name="pay_form" action="https://www.sandbox.paypal.com/cgi-bin/webscr" method="post">
<!-- 支付金额-->
<input type="hidden" name="amount" id="amount" value="0.5">
<!-- 自己的参数 商品条目-->
<input type="hidden" name="item_number" id="item_number" value="xiu90 coins:50">
<!-- 表示立即支付-->
<input type="hidden" name="cmd" id="cmd" value="_xclick">
<!-- 商品名称-->
<input type="hidden" name="item_name" id="item_name" value="buy xiu90 coins">
<!-- 商户订单唯一id 不可重复 -->
<!--
<input type="hidden" name="invoice" id="invoice" value="201604291655176">
 -->
 <!--支付成功后台通知地址-->
<input type="hidden" name="notify_url" id="notify_url" value="http://www.igo19.com/accounting/servlet/paypalNotify">
<!--支付成功返回地址-->
<input type="hidden" name="return" id="return" value="http://www.igo19.com/">
<input type="hidden" name="lc" id="lc" value="China">
<!--支付取消返回地址-->
<input type="hidden" name="cancel_return" id="cancel_return" value="http://www.igo19.com/">
<input type="hidden" name="currency_code" id="currency_code" value="USD">
<!--商户邮件-->
<input type="hidden" name="business" id="business" value="boruida99-facilitator@126.com">
</form>
<script language="javascript">document.pay_form.submit();</script>
</html>

上面内容在html页面打开就会进入以下页面

3、测试账号设置

上面表单中提到的商户测试账号,在注册企业帐号的时候,就会默认生成一个测试商户号和一个测试购买账号,如我注册的是boruida99@126.com,在测试平台下,sandbox下面的account中可以看到一下两个账号信息:

一个是商户账号,一个是个人账户。当然也可以自己添加账号如:

其实我添加的两个是不规范的,会在支付的时候有问题,可以支付成功,但是在后台通知里面payer_status=Pending而导致验证不通过。可添加类似原有形式的,如437407360-facilitator@126.com、437407360-buyer@126.com.如果仍有问题,建议用系统给的两个。

4、支付测试

打开上面的支付页面后,输入paypal支付sandbox的账号,支付,即支付成功,可以查看paypal账户,也可以返回原有商户网站。支付成功页面:

查看账户的页面,查看详情:

5、后台通知处理

支付成功后,paypal会异步通知到提交请求时设置的notify_url,后台收到通知后,需要将收到信息用&拼接符加上字符串cmd=_notify-validate发送到paypal验证消息的可靠性,即IPN验证,若返回VERIFIED表明验证成功,再判断支付状态,Complete为支付成功。后台通知代码如下

/**
 * Copyright (c) 2014-2015 BrdInfo Technology Company LTD.
 * All rights reserved.
 * 
 * Created on 2016年4月11日
 * Id: PaypalNotify.java,v 1.0 2016年4月11日 上午10:04:10 Administrator
 */
package com.brdinfo.account.paypal.utils;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.brdinfo.framework.client.HTTPWeb;

/**
 * @ClassName PaypalNotify
 * @author Administrator
 * @date 2016年4月11日 上午10:04:10
 * @Description TODO(这里用一句话描述这个类的作用)
 */
@WebServlet("/servlet/paypalNotify")
public class PaypalNotify extends HttpServlet

    private static final long serialVersionUID = 1L;
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException 
        service(request, response);
    

    @Override
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException 
        service(request, response);
    

    protected void service(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException 
        logger.info("PaypalNotify>>>>>>>>>进入paypal后台支付通知");
        PrintWriter out = response.getWriter();
        try 
            // 从 PayPal 出读取 POST 信息同时添加变量„cmd‟
            Enumeration en = request.getParameterNames();
            String str = "cmd=_notify-validate";
            while(en.hasMoreElements())
                String paramName = (String) en.nextElement();
                String paramValue = request.getParameter(paramName);
                str = str + "&" +paramName + "=" + URLEncoder.encode(paramValue,PayConfig.charset);
            
            logger.info("paypal支付请求验证参数,验证是否来自paypal消息:" + str);
            // 将信息 POST 回给 PayPal 进行验证    测试环境先省略这一步
            //HTTPWEB是我自己的类 网上有很多HTTP请求的方法
            String result = HTTPWeb.postLocalSSL(PayConfig.requestUrl, str);
            logger.info("paypal支付确认结果result="+result);


            // 将 POST 信息分配给本地变量,可以根据您的需要添加
            // 该付款明细所有变量可参考:
            // https://www.paypal.com/IntegrationCenter/ic_ipn-pdt-variable-reference.html
            String paymentStatus = request.getParameter("payment_status");
            //付款金额
            String paymentAmount = request.getParameter("mc_gross");
            //订单id
            String orderId = request.getParameter("invoice");
            if ("VERIFIED".equals(result))  
                if("Completed".equals(paymentStatus))
                      //根据项目实际需要处理其业务逻辑
                

           else if ("INVALID".equals(result)) 
                logger.info("paypal完成支付发送IPN通知返回状态非法,请联系管理员,请求参数:" + str);     
                out.println("confirmError");   
            else 
                logger.info("paypal完成支付发送IPN通知发生其他异常,请联系管理员,请求参数:" + str);  
                out.println("confirmError");   
           
         catch (IOException e)
            logger.info("确认付款信息发生IO异常" + e.getMessage());
            out.println("confirmError");   
        
        out.flush();
        out.close();        
    

6、常见问题

6.1 如何设置支付返回地址

在提交的表单中设置return_url,生产平台可以在商户信息中设置,商户返回地址设置:

     登录商户账户->用户信息->销售工具->网站习惯设定->更新->开启并设定url

6.2 paypal支付成功后后台收不到IPN通知

解决方案;
sandbox环境下提交支付请求时是否配置了notify_url,这个地址必须是外网地址,外网可以访问的到。
生产环境可以在提交表单中配置inotify_url,或者在商户工具里面配置。配置方法;

    登录商户账户->用户信息->销售工具->及时付款通知->更新->开启及时通知并设置url

配置的地址可以在IPN Simulator 模拟测试。

测试地址https://developer.paypal.com/developer/ipnSimulator/ 

该模拟器发送IPN消息到后台,后台日志打印出来可以查看收到的消息

我在做的过程中,遇到设置了一个外网地址,IPN测试可以收到,到支付成功就是收不到,最终联系客服,paypal客服说他们的服务有点问题,可能没及时发消息。真是晕啊!!!!大家遇到了也别着急,等等说不定服务就好了。

6.3 sandbox下paypal支付失败

paypal测试环境下支付,先登录sandbox账号,再发起支付。

6.4 paypal支付成功验证失败

paypal支付成功,返回结果里面payer_status=Pending,因而验证失败。

解决方案一:
先检查一下自己设置的商户邮箱和用户支付邮箱,是否正确,最好是sandbox自带的两个测试账号。自己添加的测试账号有时会出问题。
解决方案二:
检查sandbox下account设置

1)Go to PayPal Developer Website
2)Log in to your developer account
3)Click Applications
4)Click Sandbox accounts
5)Click on to the email address that you would like to turn off the Payment Review option and click Profile after it expand
6)Click Settings
7)And select Off for the Payment review.
8)Click Close

6.5 paypal支付乱码支付失败

后台服务编码需要与paypal保持一直才能验证用过,生产平台上面设置如下;

登录商户账户->用户信息->销售工具->更多销售工具->paypal按钮语言编码->与网站统一设为UTF-8

6.6 支付成功后IPN验证报错

支付成功后收到paypal后台通知,加上cmd=_notify-validate通过HTTP发送到paypal时报错,错误信息如下:

 Paypal Sandbox API: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1959)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1077)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:563)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1300)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:338)
    at com.paypal.core.HttpConnection.execute(HttpConnection.java:93)
    at com.paypal.core.rest.PayPalResource.execute(PayPalResource.java:367)
    ... 36 more

这个错误的原因是paypal不再支持TLS1,看下面的说应该更准确:

Although SunJSSE in the Java SE 7 release supports TLS 1.1 and TLS 1.2, neither version is enabled by default for client connections. Some servers do not implement forward compatibility correctly and refuse to talk to TLS 1.1 or TLS 1.2 clients. For interoperability, SunJSSE does not enable TLS 1.1 or TLS 1.2 by default for client connections.
To enable TLS 1.2 you can use the following setting of the VM: -Dhttps.protocols=TLSv1.1,TLSv1.2 Then it will work.

If you want to see more details about the handshake you can use this VM option: -Djavax.net.debug=all

Then you may confirm that TLS 1.2 is disabled if you see something like this:

*** ClientHello, TLSv1

After the server response is read the exception will be thrown. Java 8 has no such problem because TLS 1.2 is enabled by default.

Currently only the sandbox is affected. You can read on PayPal's site:

PayPal is updating its services to require TLS v1.2 for all HTTPS connections on June 17, 2016. After that date, all TLS v1.0 and TLS v1.1 API connections will be refused.

解决方案:

1、换成jdk1.8,默认支持TLS1.2,我试了下,换成jdk1.8就能验证成功
2、修改运行环境的配置
Eclipse的VM环境参数设置加上-Dhttps.protocols=TLSv1.1,TLSv1.2

-Xms256M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=256M -Dhttps.protocols=TLSv1.1,TLSv1.2

Tomcat运行环境中修改,修改tomcat的catalina.sh,在JAVA_OPTS后面加上-Dhttps.protocols=TLSv1.1,TLSv1.2

参考:http://stackoverflow.com/questions/34963083/paypal-sandbox-api-javax-net-ssl-sslhandshakeexception-received-fatal-alert-h/34964207

以上是关于paypal支付 paypal网站付款标准版问题解决的主要内容,如果未能解决你的问题,请参考以下文章

PayPal 网站付款标准错误

使用 Paypal 网站付款标准购买后显示用户的电子邮件

Paypal Business Standard:付款后如何处理?

PayPal 的自适应支付 API 和分期付款链​​式支付

Django Paypal 订阅

Paypal接受INR付款