Angular 6 Redirect to external url using POST

Saif picture Saif · Nov 25, 2018 · Viewed 7.6k times · Source

I am trying to incorporate payment gateway into angular app, I found following JavaScript snippet provided by the payment partner for incorporation, I tweaked it by adding ngNoForm and got it working with angular; stackBlitz

<form ngNoForm method="post" action="https://test.pesopay.com/b2cDemo/eng/payment/payForm.jsp">
<input type="hidden" name="amount" value="1" >
<input type="hidden" name="currCode" value="608" >
<input type="hidden" name="payMethod" value="CC">
<input type="submit" name="submit">
</form>

Next instead of using HTML <Form> POST + Action directly from component template, I wanted to make a REST call to my back end server perform some other steps and map that API response into what my payment partner expects and and then redirect to my payment partner using HttpClient POST which would supposedly do the same thing and redirect to the payment partner website which is supposed to take care of the payment process, so in short I wanted to achieve the same thing programmatically, I tried:

redirectToPaymentHandler(): Observable<any> {
  const urlEncodeData = 'amount=1&currCode=608&payMethod=CC';
  let headers = new HttpHeaders();
  headers = headers.append('Content-Type', 'application/x-www-form-urlencoded');
  headers = headers.append('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8');

  return this.httpClient.post('https://test.pesopay.com/b2cDemo/eng/payment/payForm.jsp',
    urlEncodeData, {
      headers,
      responseType: 'text'
    }).pipe(catchError((error) => {
      console.log(error)
      return EMPTY;
    }));
}

Initially I encountered CORS issue, but I was able to bypass that using Angular CLI's proxy config, now what happens is that instead of redirecting to the payment partner's website, HttpClient's POST method actually returns the web page as a string from the service endpoint, which is not what I though it would do,

Kindly refer to this stackBlitz, for further understanding.

So to sum it all up, basically I am seeking to transform above working template driven POST request into programmatic version. so I could perform some set of operations first and then redirect to the external URL using POST. I believe what I am trying programmatically is probably different from what happens against Html <form> POST + Action. There must be some programmatic equivalent of the same thing.

P.S: I did found this similar question but sadly it has no working answer.

P.S.S: I can not use window.location.href or RouterLink as its supposed to be POST and there is supposed to be info like amount, currency and other things to be passed to the payment partner along side.

Answer

Jak Ratiwanich picture Jak Ratiwanich · Dec 7, 2018

Initially I didn't think this would work, but after spending the whole week researching and trial and error. It is working nicely for me using Angular 6. You probably can use javascript or any other language you want. Basically, 2 steps you must follow:

1) When calling the login form redirect, you must set respontType=text so HttpClient won't throw an error expecting JSON data.

return  this.http.post(this.HOST_URL+'login' ,params1.toString(), 
{
    headers:  headers,
    withCredentials: true,
    observe: 'response',
    params: params1,
    responseType: 'text',
    reportProgress: true
})

2) Setup an interceptor to intercept your subsequence API request (assuming the endpoint will return json now). In the intercepter, pass withCredentials=true . In Javascript or Curl, you would expect to retrieve that from the login successful and send back JSESSIONID with the API request. In Angular, you only need withCredentials=true in the Interceptor. *NOTE: you cannot pass this in the HttpHeaders before making a request. See bug report here.

Here is my code snippet for Interceptor:

@Injectable()
export class WithCredentialsInterceptor implements HttpInterceptor {

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        console.log("Intercepting Request withCredentials=true ");
        request = request.clone({
            withCredentials: true
        });

        return next.handle(request);
    }
}

Hope this will help.