PayPal REST API .net SDK - 400 Bad Requests

14
我正在沙盒环境中工作,并使用PayPal REST .net SDK的Payment.Create方法和CreditCard对象。 当所有参数都有效且使用https://developer.paypal.com/webapps/developer/docs/integration/direct/accept-credit-cards/中提供的测试信用卡号时,该方法将返回Payment对象,一切正常。
然而,当参数无效时,例如过期日期已过或沙盒不识别的CC号码,Payment对象将不会返回。 相反,该方法会抛出异常:“HttpConnection Execute中的异常:无效的HTTP响应 远程服务器返回错误:(400)Bad Request”,但没有进一步的说明。
当我在cURL中执行相同的请求时,除了“400 Bad Request”之外,我还收到JSON响应。 这包括更有用的消息,例如“VALIDATION_ERROR”和“Invalid expiration(不能过去)”。
我的问题是:是否有一种方法可以从SDK获取这些消息?
我尝试过的方法:
  • PayPal文档: https://developer.paypal.com/webapps/developer/docs/api/#errors 此文档提到,在发生错误的情况下,他们会在响应体中返回详细信息。不幸的是,它并没有给出关于这些信息是否可以被SDK访问的线索。
  • 各种谷歌和SO搜索结果。
  • SDK提供的PizzaApp示例代码没有任何异常处理或进一步解决此问题的见解。
  • 我在SDK中看到了一个PayPalException对象,但没有找到任何指示它如何使用或是否与此问题相关的信息。

非常感谢您的帮助。

8个回答

22

我今天才开始研究SDK和API,然后立刻遇到了这个问题。我的意思是,如果我要创建自己的表单来处理付款,我希望在出现任何错误时能够向用户提供反馈。

无论如何,我在内部异常中找到了一些隐藏信息。也许这会有所帮助。

catch (PayPal.Exception.PayPalException ex)
{
    if (ex.InnerException is PayPal.Exception.ConnectionException)
    {
        context.Response.Write(((PayPal.Exception.ConnectionException)ex.InnerException).Response);
    }
    else
    {
        context.Response.Write(ex.Message);
    }
}

最终的响应:

{"name":"VALIDATION_ERROR","details":[{"field":"payer.funding_instruments[0].credit_card.number","issue":"Must be numeric"}],"message":"Invalid request - see details","information_link":"https://developer.paypal.com/webapps/developer/docs/api/#VALIDATION_ERROR","debug_id":"0548e52ef9d95"} 

不幸的是,目前似乎无法正常工作。在API的最新版本中,“Response”不再是ConnectionException的元素。然而,在尝试这个过程中,我发现如果你直接捕获PaymentsException而不是作为InnerException,它是可以工作的。我已经编辑了我的答案,提供了另一种解决方案。 - Jonathan Black

7

由于似乎没有人知道答案,所以我研究了PayPal的.NET SDK for REST API源代码。经过审核,截至目前版本,似乎没有提供在服务器返回任何4xx或5xx HTTP状态代码时返回错误消息的方法。我参考了这个问题的答案,并修改了SDK以允许在适用时返回错误响应。以下是HttpConnection.cs的相关部分。

catch (WebException ex)
{
    if (ex.Response is HttpWebResponse)
    {
        HttpStatusCode statusCode = ((HttpWebResponse)ex.Response).StatusCode;
        logger.Info("Got " + statusCode.ToString() + " response from server");
        using (WebResponse wResponse = (HttpWebResponse)ex.Response)
        {
            using (Stream data = wResponse.GetResponseStream ())
            {
                string text = new StreamReader (data).ReadToEnd ();
                return text;
            }
        }                           
    }
    if (!RequiresRetry(ex))
    {
        // Server responses in the range of 4xx and 5xx throw a WebException
        throw new ConnectionException("Invalid HTTP response " + ex.Message);
    }                       
}

当然,这需要调用函数进行更改,以便正确解释错误响应。由于我只使用了Payment Create API,所以采取了一些捷径,通常情况下不起作用。但是,基本思想是我创建了PaymentError和Detail类,然后修改了Payment.Create和PayPalResource.ConfigureAndExecute方法来填充并传回一个PaymentError对象。
三年后,PayPal的API错误响应处理有所改进。由于其他问题,我不得不重新设计我的应用程序,并摆脱之前的代码。我发现现在可以捕获PayPal.Exception.PaymentsException,然后将JSON响应字符串反序列化为PayPal.Exception.PaymentsError对象。
Catch ex As PayPal.Exception.PaymentsException
    Dim tmpPmtErr As PayPal.Exception.PaymentsError = _
        JsonConvert.DeserializeObject(Of PayPal.Exception.PaymentsError)(ex.Response)

感谢另一个回答中的@lance提醒我更仔细地检查异常。我尝试使用那个解决方案,但无法使其工作。


2

看起来情况已经有所改变,虽然很多答案都指出了正确的方向,但是没有一个完全适合我。以下是目前得到最高赞的答案的等价版本:

catch (PayPal.PaymentsException ex)
{
    context.Response.Write(ex.Response);
}

响应内容:

{"name":"VALIDATION_ERROR","details":[{"field":"start_date","issue":"Agreement start date is required, should be valid and greater than the current date. Should be consistent with ISO 8601 Format"}],"message":"Invalid request. See details.","information_link":"https://developer.paypal.com/docs/api/payments.billing-agreements#errors","debug_id":"8c56c13fccd49"}

谨慎:据我最近所见,PayPal似乎正在逐渐放弃其REST API,至少在信用卡处理方面如此。目前我的客户似乎收到了混合的信号。我正在将我的开发转移到其他地方。 - Jonathan Black

1

@Jonathan,REST API已经集成了log4net,并且如果您进行设置,它将会将完整的错误响应输出到日志文件中。您必须将以下配置部分添加到您的web.config文件中:

<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>

并设置选项:

<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
  <file value="rest-api.log"/>
  <appendToFile value="true"/>
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] %message%newline"/>
  </layout>
</appender>
<root>
  <level value="DEBUG"/>
  <appender-ref ref="FileAppender"/>
</root>

打开您的global.asax文件并将以下内容添加到Application_Start方法中:
log4net.Config.XmlConfigurator.Configure();

现在,只要您的日志文件夹设置了写入权限,PayPal REST SDK 就会将错误消息输出到日志文件中。

感谢您的回复。我会记住这个建议,以备将来应用。不幸的是,在这种情况下,这并没有帮助到我,因为我需要在应用程序范围内返回错误响应。此外,该应用程序是Windows Forms,但我认为可以通过对app.config进行类似的更改来启用相同的日志记录。 - Jonathan Black
我在尝试构建连接到PP API的代码时遇到了这个问题,想知道是否有办法让记录的内容也返回?否则,当卡被拒绝(例如无效号码、过期卡等)时,400/Bad Request 告诉我们它没有工作的原因,但并不清楚具体是什么。 - Scott Salyer
@digitall,没错!这就是为什么我不得不使用第一篇答案中提到的hack。我从未找到使用原始API的方法,正如你所提到的,应用程序内的日志记录并没有多大帮助。 - Jonathan Black

0
我的问题是,我的totaldetail.subtotalitems.price传递的值类似于$1,000.00,需要使用小数点,例如:
total = Regex.Replace(model.OrderTotal, "[^0-9.]", "")

0
改进这里的解决方案很简单(导入PayPal)。
    Try
    Catch ex As PaymentsException
        For Each i In ex.Details.details
            Response.Write(i.field) 'Name of Field
            Response.Write(i.code) 'Code If Any
            Response.Write(i.issue) 'Validation Issue
        Next
    End Try

0

以上所有的解决方案都没有真正掌握问题...

我之前遇到过类似的问题...在调试代码后,我发现我所进行的交易在逻辑上是错误的...小计金额偏差了0.25美元,PayPal服务器注意到了这一点并拒绝处理它,并给了我400个错误请求。


-1

如果您在美国以外的地区使用全球化功能,您需要将小数转换为不变文化(InvariantCulture):

order.GetTotal().ToString("N2", CultureInfo.InvariantCulture)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接