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
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.
var iframe = $('<iframe src="'+url+'" style="display:none"></iframe>').appendTo($('#main')).load(function(){
iframe.get(0).contentWindow.print();
});
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.
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.
There is a workaround for this.
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)
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With