POST-запрос на сторонний URL-адрес от Angular / NodeJS / ExpressJS - PullRequest
4 голосов
/ 24 марта 2020

Вариант 4.2 кажется мне лучшим направлением. У кого-нибудь есть другие предложения?

Есть ли способ получить ответ в любом из нижеприведенных сценариев ios или мне нужно переписать весь лог c?


I необходимо выполнить форму POST для стороннего поставщика платежей с Angular Typescript с или без NodeJS / ExpressJS с перенаправлением.

Поток:

enter image description here

Проблема заключается в том, что в некоторых случаях при успешном выполнении перенаправления URL-адреса я не получаю любой ответ от платежного шлюза . Когда пользователь нажимает «Оплатить» - «Плати», он перенаправляется на страницу успеха http://example.com/success и в случае ошибки реагирует на страницу http://example.com/cancel.

enter image description here

Ожидаемый сценарий

Пользователь заходит на сайт, выбирает товары и нажимает кнопку покупки. В этот момент он переходит на другую страницу, где он / она производит платеж. После успешной оплаты пользователь перенаправляется обратно на веб-сайт, и Я получаю ответ с сервера и показываю пользователю соответствующее сообщение.

Вариант 1 - URL-адрес действия формы

Если я отправлю стандартную форму и введу URL шлюза оплаты в [action]="'https://test-wallet.example.com/checkout/'", то пользователь будет перенаправлен непосредственно на этот URL, и платеж будет успешно обработан. Но в этом случае я не получаю ответ, который необходим мне, чтобы знать, какие данные показывать пользователю - сообщение об успехе или ошибке.

<form [action]="'https://test-wallet.example.com/checkout/'" ngNoForm method="POST" target="_blank">
      <button type="submit">Pay with card</button>
      <input name='param1' value='param1'>
      <input name='param2' value='param2'>
      <input name='param3' value='param3'>
      <input name='param4' value='param4'>
      <input name='param5' value='param5'>
      <input name='param6' value='param6'>
      <input name='param7' value='param7'>
      <input name='param8' value='param8'>
      <input name='param9' value='param9'>
</form>

Вариант 2 - HttpClient через службу

Я также пытался сделать запрос HttpClient POST внутри приложения Angular и без NodeJS бэкэнда. В этом случае я вызываю URL Платежного шлюза напрямую, но с ошибкой CORS.

payment.service.ts:

payFunction(parameters: any){
   return this._httpClient.post('https://test-wallet.example.com/checkout/'+ 
      'param1='+parameters.param1+ 
      '&param2='+parameters.param2+
      '&param3='+parameters.param3+ 
      '&param4='+parameters.param4+ 
      '&param5='+parameters.param5+
      '&param6='+parameters.param6+ 
      '&param7='+parameters.param7+
      '&param8='+parameters.param8+
      '&param9='+parameters.param9
      ,parameters
      ,this.httpOptions 
    )
   .catch(err => {
      console.log(err);
      return Observable.of(err)
   })
}

Я вызываю предыдущую службу в компоненте:

async test(form){
  await this._myPaymentService.payFunction(form.value).subscribe(res => {
        console.log(res);
})

В этом случае я получил только ошибку CORS.

enter image description here

Опция 3 - jQuery AJAX

Я вызываю это внутри моего Angular компонента с кросс-доменным contentType .

Но я также получил только ошибку CORS, как в случае выше. Я знаю, что использование jQuery в приложении Angular не по книге, но мне пришлось попробовать.

 $.ajax({
   headers: { 
     'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
   },
   url : 'https://test-wallet.example.com/checkout/',
   type: "POST",
   beforeSend: function(xhrObj){
       xhrObj.setRequestHeader('Content-Type':  'application/x-www-form-urlencoded; charset=UTF-8');
   },
   dataType : "json",
   async:true,
   crossDomain:true,
   data: corvusDataObject,
   error: function () {
     alert('Ajax Error');
   },
   onFailure: function () {
     alert('Ajax Failure');
   },
   statusCode: {
     404: function() {
       alert("Ajax 404");
     }   
   },
   success : function (response) {
     alert("Success: " + JSON.stringify(response));
     }
   })
   .done(function( data ) {
   alert("Done: " + JSON.stringify(response));
});

Вариант 4 - NodeJS / ExpressJS Backend

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

В приложении Angular я вызываю свой API:

<form [action]="'http://localhost:8080/myPaymentAPI/'" ngNoForm method="POST" target="_blank">
      <button type="submit">Pay with card</button>
      <input name='param1' value='param1'>
      <input name='param2' value='param2'>
      <input name='param3' value='param3'>
      <input name='param4' value='param4'>
      <input name='param5' value='param5'>
      <input name='param6' value='param6'>
      <input name='param7' value='param7'>
      <input name='param8' value='param8'>
      <input name='param9' value='param9'>
</form>

В NodeJS / ExpressJS Я сделал myPaymentAPI API с 307 перенаправлениями ( из этого ответа SO ).

    var express = require('express');
    var app = express();
    var cors = require('cors')  // CORS
    var bodyParser = require('body-parser'); 

    app.use(bodyParser.urlencoded({ extended: true }));
    app.use(bodyParser.json());
    app.use(cors());

    var port = process.env.PORT || 8080;
    var apiRoutes = express.Router();

    apiRoutes.get('/', function(req, res) {
        res.json({ message: 'API works!' });
    });

    app.use('/api', apiRoutes);

    app.post('/myPaymentAPI', function(req, res, next) {

      let param1 = req.body.param1;
      let param2 = req.body.param2;
      let param3 = req.body.param3;
      let param4 = req.body.param4;
      let param5 = req.body.param5;
      let param6 = req.body.param6;
      let param7 = req.body.param7;
      let param8 = req.body.param8;
      let param9 = req.body.param9;

    res.status(200).redirect(307, 'https://test-wallet.example.com/checkout/?param1='+param1 +'&param2='+param2+...)
    //res.end();

    });

Выше перенаправления переводит пользователя на URL (см. Первое изображение): https://test-wallet.example.com/#/checkout/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx и пользователь по этому URL делает платеж, но я, опять же, не получаю никакого ответа.

Опция 4.1

fetch возвращает HTML страницу, но с пустым <body>

app.post('/myPaymentAPI', function(req, res, next) {

    const url = 'https://test-wallet.example.com/checkout/?param1='+param1+'&param2='+param2+'&param3='+param3+'&param4='+param4+'&param5='+param5+'&param6='+param6+'&param7='+param7+'&param8='+param8+'&param9='+param9;
       fetch(url, {
           method : "POST",
           body: res.body
       }).then(
           response => response.text()
       ).then(
         html => res.send(html)
      ).catch((err) => {
         reject(err);
       });

});

Опция 4.2

При таком подходе я успешно получаю короткую версию URL (см. Первое изображение), а затем перенаправляю пользователя на этот URL.

    app.post('/myPaymentAPI', function(req, res, next) {

      let param1 = req.body.param1;
      let param2 = req.body.param2;
      let param3 = req.body.param3;
      ...

      try{
        var body = JSON.stringify(req.body);
        const url = 'https://test-wallet.example.com/checkout/?param1='+param1+'&param2='+param2+...;
        var newData = await fetch(url, {method: "POST", body: body})
        console.log(newData.url)
        res.redirect(307, newData.url);
      }catch(error){
        console.log(error)
      }

});

Эта страница открывается после 307 перенаправлений. В сообщении говорится: «Ваш запрос не может быть обработан. Приносим извинения, произошла ошибка».

Нужно ли на этом шаге еще раз добавить FormData перед выполнением этого перенаправления?

enter image description here

Опция 4.3

В этом подходе я вызываю мой API и создаю объект внутри res.send, который затем отправляю на мой веб-интерфейс.

try{
     var body = JSON.stringify(req.body);
     const url = 'https://test-wallet.example.com/checkout/?param1='+param1+'&param2='+param2+'&param3='+param3+...;
       await fetch(url, {method: "POST", body: body}).then((response) => {
         const data = response;
         res.send({
           success: true,
           redirectURL: data.url,
           body: req.body
         })
      })
       .catch((error) => {
         console.error(error);
       })
   }catch(error){
     console.log(error)
}

На веб-интерфейсе я успешно получаю redirectURL и body данные и пытаюсь выполнить перенаправление.

this._myPaymentService.payFunction(form.value).subscribe(res => {
            console.log(res);
            console.log(res.redirectURL);
            window.location.replace(res.redirectURL);
})

Затем веб-браузер переходит к следующему страница с пустым содержимым.

enter image description here

Поскольку запрос стал GET. Я знаю, что отправить запрос POST таким способом невозможно, и я ищу способ сделать это.

enter image description here

Ответы [ 2 ]

2 голосов
/ 02 апреля 2020

Ух ты, похоже, ты очень хочешь писать код, но на самом деле не хватает некоторых основ. Хотите ли вы иметь СПА или иметь старую форму POST? Конечно, вы получаете ошибку CORS, когда пытаетесь отправить прямой запрос API.

Я весьма обеспокоен результатом этого, поскольку вы на самом деле имеете дело с платежами и, похоже, не очень много знаете об архитектуре - возможно, я я не прав Вы слышали о OW ASP или CSRF? Вы думали о хранении транзакций на случай, если случится что-то плохое? Вы защищали от пользователей, отправляющих плохие запросы с отрицательными числами? Как насчет

Дайте себе и карманам своих пользователей некоторое утешение и прочитайте сначала, прежде чем писать код, go, по крайней мере, на нескольких примерах, например, Angular Тур героев.

Здесь это основной поток c того, как он должен выглядеть.

Бэкэнд здесь переводчик. Он предоставляет API, преобразует данные, отправленные пользователем (после проверки), в запрос, необходимый поставщику платежей. После получения результата он преобразует ответ в определенный ответ для приложения Angular - что-то, что будет сообщением об успехе или ошибке. Тогда приложение Angular может решить, что делать: показать пользователю сообщение об ошибке или об ошибке.

И! Вы всегда получаете сообщение от провайдера платежей, если на самом деле нет, вам следует ввести тайм-аут и отреагировать с сообщением об ошибке пользователю.

Удачи, я действительно молюсь, чтобы вы узнали о некоторых мерах безопасности и внедрили их. .

enter image description here

1 голос
/ 31 марта 2020

Эти 2 подхода кажутся правильными:

  • Вариант 1
  • Вариант 4 (с сервером nodejs - до версии 4.1, где оплата прошла успешно)

Однако, есть поток, который кажется отсутствующим . После осуществления платежа сервер API платежей отправляет запрос на номер http://example.com/success или http://example.com/cancel, и в теле вы найдете параметры. Таким образом, вы не можете напрямую использовать URL, чтобы показать пользователю информацию на экране (браузер на стороне клиента).


Что вам нужно сделать, это:

  • Есть сервер узла (или ваш внутренний API-сервер также будет работать), и используйте app.post для обработки URL-адреса на сервере - как вы делаете для app.post('/myPaymentAPI',).
  • Обновите базу данных или получите соответствующий платеж детали или идентификатор из req.body et c.
  • Создайте новый URL-адрес, например https://yourwebsite.com/payment?status=SUCCESS&other-info или https://yourwebsite.com/payment/id
  • Перенаправьте пользователя на определенный URL-адрес в браузере
  • То конкретный URL будет иметь детали или идентификатор. Вы можете показать соответствующую информацию или получить идентификатор и сделать вызов API по мере необходимости
app.post("http://example.com/success", function(req, res){
  //get the req.body/params here which Payment Server will post to success url
  //update your backend etc about payment status etc
  //redirect to your custom page from here https://yourwebsite.com/payment?status=success&id=id or similar
})

app.post("http://example.com/cancel", function(req, res){
  //get the req.body/params here which Payment Server will post to cancel url
  //update your backend etc about payment status etc
  //redirect to your custom page from here https://yourwebsite.com/payment?status=failure&id=id
})

Надеюсь, это поможет. Возврат для любых сомнений / разъяснений

...