最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - print a pdf via iframe (cross domain) - Stack Overflow

programmeradmin2浏览0评论

I need to print a PDF... But I get an error

Is there a workaround? I just need to print a PDF file with one click

error:

Uncaught SecurityError: Blocked a frame with origin "; from accessing a frame with origin ";. Protocols, domains, and ports must match.

code:

var iframe = $('<iframe src="'+url+'" style="display:none"></iframe>').appendTo($('#main')).load(function(){
    iframe.get(0).contentWindow.print();
});

I need to print a PDF... But I get an error

Is there a workaround? I just need to print a PDF file with one click

error:

Uncaught SecurityError: Blocked a frame with origin "https://secure.domain.com" from accessing a frame with origin "https://cdn.domain.com". Protocols, domains, and ports must match.

code:

var iframe = $('<iframe src="'+url+'" style="display:none"></iframe>').appendTo($('#main')).load(function(){
    iframe.get(0).contentWindow.print();
});
Share Improve this question edited Jun 20, 2020 at 9:12 CommunityBot 11 silver badge asked Jul 2, 2016 at 20:49 clarkkclarkk 27.7k76 gold badges222 silver badges365 bronze badges 2
  • Well, I believe the error message is quite descriptive: Protocols, domains, and ports must match. secure.domain.com is not the same as cdn.domain.com. – Derek 朕會功夫 Commented Jul 3, 2016 at 0:25
  • there must be a workaround – clarkk Commented Jul 3, 2016 at 10:00
Add a comment  | 

6 Answers 6

Reset to default 7 +100

The error you are dealing with is related to cross-domain protection and the same-origin policy.

In your case, you can print an cross-domain iframe if you nest this iframe in another local iframe that we can call a proxy iframe.

Since the proxy iframe is local and have the same origin, you can print it without any issue and it'll also print the cross-domain iframe.

See below for an example:

index.html (container)

$(function() {
  var url = 'proxy.html'; // We're not loading the PDF but a proxy which will load the PDF in another iframe.

  var iframe = $('<iframe src="' + url + '"></iframe>').appendTo($('#main'));

  iframe.on('load', function(){
    iframe.get(0).contentWindow.print();
  });
});

proxy.html (proxy)

<body>
  <iframe src="http://ANOTHER_DOMAIN/PDF_NAME.pdf"></iframe>
</body>

With this solution, you no longer have cross-domain issues and you can use the print() function. The only things you need to deal with are a way to pass the PDF url from the container to the proxy and a way to detect when the iframe with the PDF is actually loaded but these depends on the solution / languages you're using.

I needed to print a PDF embedded through a data:application/pdf;base64,… iframe, and I ran into the same cross-origin issue.

The solution was to convert the Base64 contents that I had into a blob, and then use put blob's object URL into the iframe src. After doing that I was able to print that iframe.

I know link-only answers are discouraged, but copying someone else's answers into my own didn't feel right either.

There is a workaround for this.

  1. Create an endpoint in your server to return the HTML content of the external url. (because you can't get external content from the browser - same-origin policy)

  2. Use $.get to fetch the external content from your URL and append it to an iframe.

Something similar to this:

HTML:

<div id="main">
    <iframe id="my-iframe" style="display:none"></iframe>
</div>

JS:

$.get('https://secure.domain.com/get-cdndomaincom-url-content', function(response) {
    var iframe = $('#my-iframe')[0],
        iframedoc = iframe.contentDocument || iframe.contentWindow.document;

    iframedoc.body.innerHTML = response;
    iframe.contentWindow.print();
});

C# implementation for get-cdndomaincom-url-content:

Easiest way to read from a URL into a string in .NET

You do not need proxy server for workaround. You can create proxy iframe and then dynamically create another iframe inside the proxy iframe. Then attach onload="print()" to it.

Something like this

  /**
   * Load iframe from cross-origin via proxy iframe
   * and then invokes the print dialog.
   * It is not possible to call window.print() on the target iframe directly
   * because of cross-origin policy.
   * 
   * Downside is that the iframe stays loaded. 
   */
  function printIframe(url) {
    var proxyIframe = document.createElement('iframe');
    var body = document.getElementsByTagName('body')[0];
    body.appendChild(proxyIframe);
    proxyIframe.style.width = '100%';
    proxyIframe.style.height = '100%';
    proxyIframe.style.display = 'none';

    var contentWindow = proxyIframe.contentWindow;
    contentWindow.document.open();
    // Set dimensions according to your needs.
    // You may need to calculate the dynamically after the content has loaded
    contentWindow.document.write('<iframe src="' + url + '" onload="print();" width="1000" height="1800" frameborder="0" marginheight="0" marginwidth="0">');
    contentWindow.document.close();
  }

--Issue--

HiDeo is right this is a cross-domain issue. It is a part of CORS which is a great thing for the security of the web but also a pain.

--Philosophy--

There are ways to work around CORS but I believe in finding a solution that works for most to all cases and keep using it. This creates easier code to reason about and keeps code consistent rather then changing and creating code for edge cases. This can create a harder initial solution but as you can reuse the method regardless of use case you end up saving time.

--Answer--

The way our team handles cross domain request issues is bypassing it completely. CORS is something for browsers only. So the best way to solve all cases of this issue is don't give the reasonability to the browser. We have the server fetch the document and giving it to the browser on the same domain.

(I'm an Angular guy) The client would say something like

$http.get('/pdf/x').then(function(){
    //do whatever you want with any cross-domain doument
});

The Server would have something like what you see here HTTP GET Request in Node.js Express

It is a CORS issue . There is a library that acts as a CORS alternative , you can find it here Xdomain CORS alternative Github . It kind of by-passes CORS request seamlessly to render cross domain resources effectively.

It has a Javascript, AngularJS, as well as a JQuery wrapper too . I think this will provide you a more elegant solution, and is simple to integrate. Give it a try .

发布评论

评论列表(0)

  1. 暂无评论