【问题标题】:PayPal REST API .net SDK - 400 Bad RequestsPayPal REST API .net SDK - 400 个错误请求
【发布时间】:2013-03-12 22:58:29
【问题描述】:

我正在沙箱中工作,并使用带有 CreditCard 对象的 PayPal REST .net SDK 方法 Payment.Create。当所有参数都有效并使用来自https://developer.paypal.com/webapps/developer/docs/integration/direct/accept-credit-cards/ 的测试CC 编号时,该方法会返回Payment 对象,一切正常。

但是,当参数无效时,例如过去的到期日期或沙盒无法识别的 CC 编号,则不会返回 Payment 对象。相反,该方法抛出异常:“HttpConnection Execute 中的异常:无效的 HTTP 响应远程服务器返回错误:(400)错误请求”,但没有进一步解释。

当我在 cURL 中执行相同的请求时,除了“400 Bad Request”之外,我还会收到 JSON 响应。这包括更有用的消息,例如“VALIDATION_ERROR”和“无效过期(不能是过去)”。

我的问题:有没有办法从 SDK 中获取这些消息?

我尝试过的:

  • 贝宝文档:https://developer.paypal.com/webapps/developer/docs/api/#errors 该文档提到,如果出现错误,它们会在响应正文中返回详细信息。不幸的是,它没有提供有关 SDK 是否可以访问这些内容的线索。
  • 各种 Google 和 SO 搜索。
  • SDK 提供的 PizzaApp 示例代码没有任何异常处理或进一步深入了解此问题的方式。
  • 我在 SDK 中看到一个 PayPalException 对象,但没有找到任何指示它应该如何使用或者它是否与此问题相关的任何内容。

非常感谢所有帮助。

【问题讨论】:

    标签: .net rest sdk paypal paypal-sandbox


    【解决方案1】:

    我今天才开始弄乱 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 的最新版本中,“响应”不是 ConnectionException 的元素。但是,在尝试这个的过程中,我发现如果你直接捕获 PaymentsException,而不是 InnerException,它就可以工作。我已经用替代解决方案编辑了我的答案。
    【解决方案2】:

    由于似乎没有人知道这个问题的答案,我研究了 PayPal 的 .NET SDK for REST API 的源代码。从这次审查中,似乎在当前版本中,当服务器返回任何 4xx 或 5xx HTTP 状态代码时,没有返回错误消息的规定。我参考了this question 的答案,并更改了 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 在另一个答案中的提醒,以便更仔细地检查异常。我尝试使用该解决方案,但无法使其发挥作用。

    【讨论】:

      【解决方案3】:

      这似乎已经改变了,虽然其中许多答案都指向正确的方向,但没有一个对我完全有效。这相当于我目前最受好评的答案:

      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,至少在 CC 处理方面是这样。在这一点上,我的客户似乎收到了不同的信号。我正在将我的开发转移到其他地方。
      【解决方案4】:

      @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 窗体,但我认为可以对 app.config 进行类似更改以启用相同的日志记录。
      • 我在尝试构建一个连接到 PP API 的部分时遇到了这个问题,我想知道是否有办法让记录的内容也被返回?否则,当一张卡被拒绝(例如无效号码、过期卡等)时,400/Bad Request 不会告诉我们为什么它不起作用,只是它不起作用。
      • @digitall,没错!这就是为什么我不得不使用第一个答案中提到的技巧。我从来没有找到使用股票 API 的方法,而且正如你所提到的,日志记录在应用程序内部并没有太大帮助。
      【解决方案5】:

      我的问题是我的 totaldetail.subtotalitems.price 传递了像 $1,000.00 这样的值,它需要十进制,所以使用类似的东西:

      total = Regex.Replace(model.OrderTotal, "[^0-9.]", "")
      

      【讨论】:

        【解决方案6】:

        在这里改进解决方案是......简单 (进口贝宝)

            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
        

        【讨论】:

          【解决方案7】:

          以上所有解决方法都没有真正把握问题..

          不久前我遇到了类似的问题。在调试了我的代码后,我发现我所做的交易在逻辑上是错误的。小计是 0.25 美元,而贝宝服务器看到它并拒绝处理它,并给了我 400 个错误的请求

          【讨论】:

            【解决方案8】:

            如果您在美国以外使用全球化,则需要将小数转换为 InvariantCulture:

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

            【讨论】:

              猜你喜欢
              • 2015-07-17
              • 2013-05-09
              • 2014-04-19
              • 2017-12-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-08-02
              • 2013-11-12
              相关资源
              最近更新 更多