Is there a way to add a custom http header into the request done by an <iframe>
when changing the source (src) using javascript?

- 18,225
- 5
- 35
- 52

- 2,291
- 3
- 19
- 25
4 Answers
You can have the results of an ajax request that has custom headers be set as the content of an iframe like so:
$.ajax({
type: "GET",
url: "https://app.icontact.com/icp/a/",
contentType: "application/json",
beforeSend: function(xhr, settings){
xhr.setRequestHeader("some_custom_header", "foo");},
success: function(data){
$("#output_iframe_id").attr('src',"data:text/html;charset=utf-8," + escape(data))
}
});
This is assuming the iframe is pointing at a cross domain src. It is simpler if everything is on the same domain.
Edit: Maybe try this variation.
$.ajax({
type: "GET",
url: "https://app.icontact.com/icp/a/",
contentType: "application/json",
beforeSend: function(xhr, settings){
xhr.setRequestHeader("some_custom_header", "foo");},
success: function(data){
$("#output_iframe_id").attr('src',"/")
$("#output_iframe_id").contents().find('html').html(data);
}
});

- 3,226
- 1
- 17
- 20
-
1Thanks a lot! By the way, what's the difference if it is in the same domain? – dave Jul 17 '13 at 09:56
-
2It's not working for IE :-S. In Chrome and Firefox worked, but the css rules and scripts from external file (referenced inside the frame) are not applied. – dave Jul 17 '13 at 10:27
-
give this a shot maybe – Matthew Graves Jul 17 '13 at 16:04
-
Much better! I came across that solution at http://twigstechtips.blogspot.com.es/2011/02/jquery-set-content-of-empty-iframe.html?showComment=1374147326122#c1663451605888613735 Any chance to add script blocks? Because they are not included when doing it this way. Thanks! – dave Jul 18 '13 at 11:41
-
2It is odd because if I inspect the generated html code in chrome, there's no difference between assigning to 'src' property the url (without http custom headers) and doing $("#output_iframe_id").contents().find('html').html(data); But the latter doesn't execute javascript functions defined on or external file. However it executes document.onready() function. – dave Jul 19 '13 at 09:44
-
very good stuff as for `$("#output_iframe_id").contents().find('html').html(data);`. – pt12lol Aug 24 '17 at 14:10
-
This does work for simple iframe content, but as soon as your content contains scripts trying to access the localStorage, this fails as data urls are restricted - even on the same domain. Found this out when trying to load the GraphqlPlayground with auth headers. The answer by @FellowMD does the job. - Error message from Chrome: `Uncaught DOMException: Failed to read the 'localStorage' property from 'Window': Storage is disabled inside 'data:' URLs.` – 4levels Feb 09 '19 at 17:39
-
@MatthewGraves Is there any react way of doing the same ? – Pranshu Kashyap Dec 08 '22 at 00:10
-
@MatthewGraves Should this solution be working with external relative links? From my understanding no, since `src` is not defined and link can be e.g. `/sub-page`. – Mateusz Dec 29 '22 at 10:30
Rather than using a data URI, or setting the contents to a string, you can use URL.createObjectURL()
, and set it as the src
of the iframe.
var xhr = new XMLHttpRequest();
xhr.open('GET', 'some.pdf');
xhr.onreadystatechange = handler;
xhr.responseType = 'blob';
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
xhr.send();
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
// this.response is a Blob, because we set responseType above
var data_url = URL.createObjectURL(this.response);
document.querySelector('#output-frame-id').src = data_url;
} else {
console.error('no pdf :(');
}
}
}
The object URLs are pretty interesting. They're of the form blob:https://your.domain/1e8def13-3817-4eab-ad8a-160923995170
. You can actually open them in a new tab and see the response, and they're discarded when the context that created them is closed.
Here's a full example: https://github.com/courajs/pdf-poc

- 2,142
- 3
- 16
- 15
-
This looks to be the best answer, if the URL object is available. Otherwise downgrade to accepted answer. – Ben Gripka Sep 28 '17 at 04:01
I ended up going with the approach proposed by the other answers here, that use ajax to get the html string and then directly set the contents of the iFrame
.
However, I used the approach posted in this answer to actually set the contents of the iFrame
, as I found it worked well cross platform with almost all devices I could dig up.
Tested - successful:
- Chrome 54 (desktop) ^
- Firefox 49 (desktop) ^
- IE 11 (desktop) ^
- IE 10 (desktop) in emulation mode ^
- Safari/Chrome on iOS 8 (ipad)
- Chrome on Android 6 (nexus phone)
- Edge on Lumia 950 (Win 10 Phone)
^ confirmed that linked css and js in the content run correctly (others not tested)
Tested - unsuccessful:
- IE 9 (desktop) in emulation mode
- Safari/Chrome on iOS 7 (iPhone)
So putting them together gives something like this (Note: I havn't actually run this exact code):
$.ajax({
type: "GET",
url: "https://yourdomain.com/gethtml",
beforeSend: function(xhr) {
xhr.setRequestHeader("yourheader", "value");
},
success: function(data) {
var iframeDoc = document.querySelector('#myiframe').contentWindow.document;
iframeDoc.open('text/html', 'replace');
iframeDoc.write(data);
iframeDoc.close();
}
});
Here's an example of setting the iFrame
contents in this JS Bin
Edit: Here's the html part
<iframe id="myiframe" src="about:blank"></iframe>
Edit 2:
The solution above appears to no longer be working in Firefox (50.1.0) for some unknown reason. Using the solution in this answer I've now changed to code to the example below, which also seems to be more robust:
$.ajax({
type: "GET",
url: "https://yourdomain.com/gethtml",
beforeSend: function(xhr) {
xhr.setRequestHeader("yourheader", "value");
},
success: function(data) {
var iframe = document.getElementById('myiframe');
iframe.contentWindow.contents = data;
iframe.src = 'javascript:window["contents"]';
}
});
-
1unfortunately if you load up some content using relative paths 'in-app', you will probably face with problems. Tried it with angular2 and got routing problems 'route not found'... Haven't found any answer yet. – iwazovsky Nov 27 '16 at 15:10
-
1@eatmypants Not sure what you're running into - I haven't played with angular2, but I am using this in angular1. As the call to the server is ajax, you should be able to resolve your urls in whatever way you do for any other ajax calls. Are you editing the `src` of the `iFrame` perhaps? I just leave it as `about:blank`. – Jono Job Nov 28 '16 at 02:16
-
Hi @JonoJob, I came across similiar situation where I used your solution but it did not work for me. I want to open external application within iframe. `@{ string BUrl = ViewBag.BUrl; string Token = ViewBag.Token; } $(document).ready(function () {$.ajax({url: '@BUrl'.replace(/amp;/g, ''),type: 'GET', beforeSend: function (xhr) {xhr.setRequestHeader('Authorization', 'Bearer ' + '@Token'); }, success: function (data) {$("#myiframe").attr('src', "/") $("#myiframe").contents().find('html').html(data);}}); });` – Raj Apr 06 '22 at 18:19
The following code works. It is a modification of the code provided by Matthew Graves, modified to use the srcdoc
attribute to solve the problem of CSS and JavaScript references not been ran. Unfortunately, it is only working in Chrome.
$.ajax({
type: "GET",
url: "https://app.icontact.com/icp/a/",
contentType: "application/json",
beforeSend: function(xhr, settings){
xhr.setRequestHeader("some_custom_header", "foo");},
success: function(data){
$("#output_iframe_id").attr('srcdoc',data)
}
});
Edit: Finally, I have resolved the issue of the scripts blocks cross-browser, by reassigning them to the iframe on document.ready function:
$(document).ready(function () {
var doc = $(document);
if (frames.length > 0) {
doc = frames[0].document;
$(doc).find('script').each(function () {
var script = document.createElement("script");
if ($(this).attr("type") != null) script.type = $(this).attr("type");
if ($(this).attr("src") != null) script.src = $(this).attr("src");
script.text = $(this).html();
$(doc).find('head')[0].appendChild(script);
$(this).remove();
});
}
});