Введение в PayPal для C# - разработчики ASP.NET - Моментальное уведомление о платеже (IPN)

ОГЛАВЛЕНИЕ

Моментальное уведомление о платеже (IPN)

Один крупный недостаток PDT в том, что это управляемый пользователем процесс, что означает – если пользователь закроет браузер после осуществления платежа и до переадресации на ваш сайт, вы потеряете возможность выполнить ваш алгоритм постобработки. Поэтому рекомендуется объединять PDT с IPN для любой серьезной интеграции с PayPal.

IPN – внутренний механизм, выполняющий запросы HTTP POST к вашей странице, уведомляющий вас о важных событиях. Он используется не только для обработки постоплаты, но и для происходящих после нее вещей, скажем, обработка отмены регулярных платежей пользователем.

Так как это внутренняя (серверная) технология, ее несколько труднее реализовывать и отлаживать, чем PDT. Перед началом реализации IPN нужно запомнить пару вещей:

  • Сообщения IPN иногда могут запаздывать. Это лишает смысла слово "моментальный" в IPN, но таково положение вещей.
  • Есть известная история проблем со службой IPN; две последних аварии произошли 2 октября 2009(2- часовая задержка) и 6 сентября 2009 (6- часовая задержка).
  • Всякий раз, когда у вас возникнут проблемы с IPN, обязательно проверьте страницу Состояния в реальном времени и посмотрите, есть ли уведомление об аварии, прежде чем углубляться в отладку и изменение вашего скрипта. Есть подобная страница для состояния Sandbox.

Перед тем как вы сможете получать сообщения IPN, нужно активировать эту службу; выполните следующие шаги:

  1. Войдите в ваш первый или бизнес-аккаунт
  2. Нажмите вложенную вкладку “Профиль”
  3. Нажмите “Моментальное уведомление о платеже” в колонке “Настройки продажи”
  4. Нажмите кнопку 'Редактировать настройки IPN', чтобы обновить ваши настройки
  5. Отметьте 'Получать сообщения IPN' (включено) и введите URL вашего обработчика IPN
  6. Нажмите “Сохранить”, и вы получите сообщение, что вы успешно активировали IPN

Активация Моментального уведомления о платеже

Как и в случае самовозврата, можно переписать URL обработчика IPN, заданный в профиле, в отдельных формах путем добавления переменной notify_url (смотрите справочник переменных HTML). Это влияет не только на исходное сообщение IPN, но и на все будущие сообщения, связанные с этой транзакцией (они все уйдут к notify_url).

Для обработки сообщений IPN нужно создать обработчик HTTP где-либо на вашем сайте. Когда произойдет существенное событие (например, пользователь выполнит платёж), выполнится следующая последовательность операций:

  1. PayPal отправит запрос HTTP POST вашему обработчику IPN с некоторым количеством переменных.
  2. После получения HTTP POST и его разбора нужно отправить все тело сообщения обратно в https://www.paypal.com/cgi-bin/webscr (или в https://www.sandbox.paypal.com/cgi-bin/webscr для аккаунта Sandbox). Когда делаете это, обязательно отправляйте сообщение обратно в точно таком же формате, в каком вы его получили; разрешается только добавить cmd=_notify-validate. Все этой делается с целью подтверждения, что HTTP POST  был подлинным и отправленным из PayPal.
  3. PayPal ответит “подтверждено” или “неверно”. После получения этого ответа обязательно отправьте 200 OK, чтобы предотвратить повторные попытки PayPal отправить IPN. Если не завершить цикл при помощи 200 OK, PayPal начнет повторно отправлять IPN (начиная с 4 секунд и удваивая интервал - 8 секунд, 16 секунд, 32 секунды... до 4 дней).

Здесь приведен стандартный обработчик C# IPN:

 protected void Page_Load(object sender, EventArgs e)
{    
    string postUrl = ConfigurationManager.AppSettings["PayPalSubmitUrl"];
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(postUrl);

    //Установка значений для обратного запроса
    req.Method = "POST";
    req.ContentType = "application/x-www-form-urlencoded";
    byte[] param = Request.BinaryRead(HttpContext.Current.Request.ContentLength);
    string strRequest = Encoding.ASCII.GetString(param);
    string ipnPost = strRequest;
    strRequest += "&cmd=_notify-validate";
    req.ContentLength = strRequest.Length;

    //для прокси
    //WebProxy proxy = new WebProxy(new Uri("http://url:port#"));
    //req.Proxy = proxy;

    //Отправка запроса к PayPal и получение ответа
    StreamWriter streamOut = new StreamWriter(req.GetRequestStream(),
                             System.Text.Encoding.ASCII);
    streamOut.Write(strRequest);
    streamOut.Close();
    
    StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream());
    string strResponse = streamIn.ReadToEnd();
    streamIn.Close();

    // регистрация сообщений ipn... убедитесь, что вы дали разрешение на
    // запись процессу, выполняющему этот код
    string logPathDir = ResolveUrl("Messages");
    string logPath = string.Format("{0}\\{1}.txt",
                     Server.MapPath(logPathDir), DateTime.Now.Ticks);
    File.WriteAllText(logPath, ipnPost);
    //

    if (strResponse == "VERIFIED")
    {
        //проверьте, что payment_status (состояние платежа) завершен
        //проверьте, что txn_id не был обработан раньше
        //проверьте, что receiver_email (емайл получателя) - ваш основной электронный адрес PayPal
        //проверьте, что payment_amount/payment_currency (сумма платежа/валюта платежа) правильные
        //обработка платежа
    }
    else if (strResponse == "INVALID")
    {
        //регистрация для ручного изучения
    }
    else
    {
        //регистрация данных ответа/ipn для ручного изучения
    }
}

Если получен ответ “неверно”, это может означать две вещи:

  • Кто-то пытался отправить вредоносное сообщение в ваш обработчик IPN.
  • В вашей реализации есть ошибки.

В случае вредоносного сообщения действуйте самостоятельно (запишите IP, предпримите соответствующие действия), но в случае ошибок в реализации посетите эту тему поиска и устранения ошибок IPN на форуме разработчиков PayPal; в ней много полезных советов, которые должны помочь решить проблему ответов “неверно”.

Перед перемещением в интернет вашего обработчика IPN, обязательно основательно протестируйте его при помощи симулятора моментального уведомления о платеже (IPN). Пока обработчик IPN будет работать в фоновом режиме, вам нужно максимально протестировать его перед тем, как запускать его на сайте и полагаться на его обработку.

Во время реализации IPN зайдите на страницу ScriptGenerator2... он умеет быстро генерировать обработчик IPN на выбранном вами языке. Странно, что у них нет генератора для ASP.NET/C#; для этого ознакомьтесь с папкой IPN в архиве с исходниками, прикрепленном к статье, и эти примеры кода.

Наконец, в центре разработчиков PayPal есть хорошая страница, содержащая список большинства переменных IPN и PDT. Однако некоторых переменных в нём нет (смотрите комментарии на этой страницы), но список более чем полезен.