PayPal REST API.net SDK - 400 Bad Requests

Я работаю в песочнице и использую метод PayPal REST.net SDK Payment.Create с объектом CreditCard. Когда все параметры действительны и используя номер тестового CC из https://developer.paypal.com/webapps/developer/docs/integration/direct/accept-credit-cards/, объект Payment возвращается из этого метода, и все хорошо.

Однако, когда параметр недействителен, например, прошлая дата истечения срока действия или номер CC, не распознанный песочницей, объект Payment не возвращается. Вместо этого метод генерирует исключение: "Исключение в HttpConnection Execute: Неверный ответ HTTP. Удаленный сервер возвратил ошибку: (400)" Плохой запрос ", но без дополнительных объяснений.

Когда я выполняю тот же запрос в cURL, в дополнение к "400 Bad Request", я получаю ответ JSON. Это включает в себя более полезные сообщения, такие как "VALIDATION_ERROR" и "Invalid expiration (не может быть в прошлом)".

Мой вопрос: есть ли способ вернуть эти сообщения из SDK?

Что я пробовал:

  • Документы PayPal: https://developer.paypal.com/webapps/developer/docs/api/#errors В этом документе упоминается, что в случае ошибки они возвращают детали в тексте ответа. К сожалению, он не дает понять, доступны ли они SDK.
  • Различные поисковые запросы Google и SO.
  • Пример кода PizzaApp, поставляемый с SDK, не имеет ничего общего с обработкой исключений или дальнейшим пониманием этой проблемы.
  • Я вижу объект PayPalException в SDK, но не нашел ничего, что указывало бы, как оно должно использоваться или если оно даже имеет отношение к этой проблеме.

Вся помощь очень ценится.

Ответ 1

Поскольку никто, кажется, не знает ответа на этот вопрос, я впился в исходный код SDK PayPal.NET для REST API. Из этого обзора видно, что с текущей версией нет никаких условий для возврата сообщений об ошибках, когда серверный код кода HTTP-кода 4xx или 5xx возвращается. Я ссылался на ответы на этот вопрос и изменил 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);
    }                       
}

Разумеется, для правильной интерпретации ответа на ошибку требуется изменение функции вызова. Поскольку я использую только 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

Я только начал общаться с 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"} 

Ответ 3

@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();

Теперь, если в папке журнала установлены разрешения на запись, тогда SDK PayPal REST вытолкнет сообщения об ошибках в файл журнала.

Ответ 4

Моя проблема заключалась в том, что мои total, detail.subtotal и items.price передавали значения, такие как $1,000.00, и ему нужно десятичное значение, поэтому используйте что-то вроде:

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

Ответ 5

Улучшение решения здесь... Просто (Импорт 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

Ответ 6

Все вышеприведенное решение действительно не понимает проблему.

Я столкнулся с подобной проблемой некоторое время назад. После отладки моего кода я узнал, что транзакция, которую я делал, была логически неправильной. промежуточный итог был равен 0,25 доллара, а сервер PayPal увидел его и отказался обрабатывать его, и дал мне 400 плохих запросов

Ответ 7

Это, похоже, изменилось, и хотя многие из этих ответов указывают в правильном направлении, никто из них не работал точно для меня. Это мой эквивалент в настоящее время наиболее ответного ответа:

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"}

Ответ 8

Если вы используете глобализацию за пределами США, вам нужно преобразовать десятичные знаки в InvariantCulture:

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