Search code examples
javascriptangularangular-httpclient

Angular Post to external server, display results in iframe


So I am integrating my angular application into a payment gateway, in certain instances there is an additional security check required by the payment processor. For anyone interested, its a 3D Secure implementation.

I can perform the post request no problem, but the value returned from my provider is simply....

<html>
    <head>
        <title>Redirecting...</title>

I was hoping it would return full html that I could just render in a modal, no such luck.

So I tried to create an iframe to post into and handle this (like the old school days) but I can't get this to work. My code so far...

Component

export class CheckoutComponent implements OnInit {
    @ViewChild('form') postForm: ElementRef;
    private MD: any;
    private PaReq: any;
    private TermUrl: any;
    private demoEndpoint: any;
    @ViewChild('threedsModal', { static: true }) private threedsModal;
    constructor(
        private http: HttpClient,
        ) { }

    ngOnInit(): void {
        this.demoEndpoint = 'www.example.com/post/'
        this.MD = 'foo';
        this.PaReq = 'bar';
        this.TermUrl = 'www.myexample.com/response';


    }
    onLoad() {
        console.log('onLoad triggered.');
    }
   // Called from another part of the code when we need to perform the POST
    submitForm(){

        // values are custom encoded, not needed to show for example
        const myParams = new HttpParams({encoder: new HttpUrlEncodingCodec()})
            .set('MD', this.MD)
            .set('PaReq', this.PaReq)
            .set('TermUrl', this.TermUrl);
        this.http.post(this.demoEndpoint, myParams, {responseType: 'text'}).subscribe(x => console.log(x));

        return true;
    }

}

Then in my template:

 <iframe class="custom-frame" #frame width="400" height="400" id="frame" name="frame" 
          frameborder="0" [src]="demoEndpoint | safeResourceUrl" (load)="onLoad()"></iframe>

<form target="frame" action="demoEndpoint| safeResourceUrl" #form method="POST">
    <input type="hidden" name="MD" value={{MD}} id="MD" />
    <input type="hidden" name="PaReq" value={{PaReq}} id="PaReq" />
    <input type="hidden" name="TermUrl" value={{TermUrl}} id="TermUrl" />
</form>

But this iframe simply renders "Unable to determine the request"

If I perform the POST request manually in postman, in renders the correct HTML, but the response from my httpPOST in console just shows Re-directing.

So my question, how can I achieve this in an iframe and render the correct response?

EDIT: This question helped me somewhat


Solution

  • So for the help of anyone in the future, this was fairly easy with the help of this answer

      // create a form for the post request
      const form = window.document.createElement('form');
      form.setAttribute('method', 'post');
      form.setAttribute('action', 'http://post.example.com');
      // use _self to redirect in same tab, _blank to open in new tab
      // form.setAttribute('target', '_blank');
      form.setAttribute('target', 'threedframe');
    
      // Add all the data to be posted as Hidden elements
      form.appendChild(this.createHiddenElement('MD', 'foo'));
      form.appendChild(this.createHiddenElement('PaReq', 'bar'));
      form.appendChild(this.createHiddenElement('TermUrl','https://dump.example.com'));
      console.log(form);
      window.document.body.appendChild(form);
      form.submit();
    
      // create the form
      private createHiddenElement(name: string, value: string): HTMLInputElement {
        const hiddenField = document.createElement('input');
        hiddenField.setAttribute('name', name);
        hiddenField.setAttribute('value', value);
        hiddenField.setAttribute('type', 'hidden');
        return hiddenField;
      }
    

    Then setup an iframe in my template:

     <iframe class="custom-frame" id="three-d-frame"  width="430" height="450" frameborder="0" name="threedframe">