I understand that you can set HTTP request headers very easily when making AJAX calls in JavaScript.
However is it also possible to set custom HTTP request headers when inserting an iframe into a page via script?
<iframe src="someURL"> <!-- is there any place to set headers in this? -->
You can make the request in javascript, setting any headers you'd like. Then you can URL.createObjectURL(), to get something suitable for the src of the iframe.
var xhr = new XMLHttpRequest();
xhr.open('GET', 'page.html');
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 MIME type of the response is preserved. So if you get an html response, the html will show in the iframe. If you requested a pdf, the browser pdf viewer will kick in for the iframe.
If this is part of a long-lived client-side app, you may want to use URL.revokeObjectURL() to avoid memory leaks.
The object URLs are also 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
No, you can't. However you could set the iframe source to some kind of preload script, which uses AJAX to fetch the actual page with all the headers you want.
As #FellowMD answer is not working on modern browsers due to the depreciation of createObjectURL, I used the same approach but using iframe srcDoc attribute.
Retrieve the content to display in the iframe using XMLHttpRequest or any other method
Set the srcdoc parameter of the iframe
Please find below a React example (I know it is overkill):
import React, {useEffect, useState} from 'react';
function App() {
const [content, setContent] = useState('');
useEffect(() => {
// Fetch the content using the method of your choice
const fetchedContent = '<h1>Some HTML</h1>';
setContent(fetchedContent);
}, []);
return (
<div className="App">
<iframe sandbox id="inlineFrameExample"
title="Inline Frame Example"
width="300"
height="200"
srcDoc={content}>
</iframe>
</div>
);
}
export default App;
Srcdoc is now supported on most browsers. It seems that Edge was a bit late to implement it: https://caniuse.com/#feat=iframe-srcdoc
It turns out that URL.createObjectURL() is deprecated in Chrome 71
(see https://developers.google.com/web/updates/2018/10/chrome-71-deps-rems)
Building on #Niet the dark Absol and #FellowMD's excellent answers, here's how to load a file into an iframe, if you need to pass in authentication headers. (You can't just set the src attribute to the URL):
$scope.load() {
var iframe = #angular.element("#reportViewer");
var url = "http://your.url.com/path/etc";
var token = "your-long-auth-token";
var headers = [['Authorization', 'Bearer ' + token]];
$scope.populateIframe(iframe, url, headers);
}
$scope.populateIframe = function (iframe, url, headers) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onreadystatechange = handler;
xhr.responseType = 'document';
headers.forEach(function (header) {
xhr.setRequestHeader(header[0], header[1]);
});
xhr.send();
function handler() {
if (this.readyState === this.DONE) {
if (this.status === 200) {
var content = iframe[0].contentWindow ||
iframe[0].contentDocument.document ||
iframe[0].contentDocument;
content.document.open();
content.document.write(this.response.documentElement.innerHTML);
content.document.close();
} else {
iframe.attr('srcdoc', '<html><head></head><body>Error loading page.</body></html>');
}
}
}
}
and shoutout to courajs: https://github.com/courajs/pdf-poc/blob/master/script.js
Related
I'd like to load inside a QML WebView some HTML, but I need it to be hard-typed (inline). I can't load an external URL nor a local file.
I can't use this:
WebView{
id:webView
url:"file:///android_asset/html/index.html";
}
And I can't use this:
WebView {
id: webView
Component.onCompleted: {
var resource = 'qrc:/path/to/your/resource.html';
var xhr = new XMLHttpRequest;
xhr.open('GET', resource);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE) {
var response = xhr.responseText;
webView.loadHtml(response);
}
};
xhr.send();
}
}
I specifically need to load it for example like this:
webView.loadHtml("<p>TEST</p>");
Is there any way to achieve it?
Answering my own question.
loadHtml works with inline HTML as long as you also give it a name in the second paramenter, like this:
loadHtml("<p>TEST</p>", "index.html")
I have a JavaScript function that is attempting to closely emulate a form submit.
function fopen() {
var xhr = new XMLHttpRequest();
xhr.open("POST", open_url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
create: 0,
jobtype: jobtype,
name: document.getElementById("file-selector").value
}));
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
document.write(xhr.responseText);
}
else {
console.log('ErR0r')
}
}
}
The behavior is close to identical, but the URL is not being updated after the response. I see there is an xhr.responseURL attribute but how can I actually get this to show in the address bar? And is there an exact full JavaScript implementation of form submit I can refer to in order to keep things as similar as possible?
To change the page's URL, set window.location.href.
Having this API:
http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1
How can I write using pure JS request that downloads me different data after button click event?
All I get from this code is the same quote all the time:
function getQuote (cb) {
var xmlhttp = new XMLHttpRequest();
var quoteURL = "http://quotesondesign.com/wp-json/posts?filter[orderby]=rand"
xmlhttp.onreadystatechange = function() {
if (xmlhttp.status == 200 && this.readyState==4) {
cb(this.responseText);
}
};
xmlhttp.open("GET", quoteURL, true);
xmlhttp.send();
}
document.querySelector('button').addEventListener("click", function() {
getQuote(function(quote) {
console.log(quote);
});
})
I tried xmlhttp.abort() and stuff but it didnt want to cooperate.
Thanks in advance!
Your response is being cached by the browser. A common trick to avoid this is to perform a request to
http://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&r={random_number}
Notice how the r={random_number} will make the URL different each time.
This is a caching problem. Add a timestamp as a query parameter and you should be able to bust the cache.
In my HTML document, there is a image
<img src="https://www.gravatar.com/avatar/1d9c87a4d5cbcae4c76e867cb6861fa0?s=48&d=identicon&r=PG&f=1"/>
When open this document in browser, E.g. Chrome, we can find the Content-Type of this image is "image/png" in Chrome Developer Tools -> Network tab according to the HTTP response headers.
How can I get the Content-Type using JavaScript after the image loading.
More specifically, what I need is a function like below.
/**
* #param {HTMLImageElement} img
* #return {String} the content type, e.g. "image/png", "image/svg+xml"
*/
getImgContentType(img) {
// TODO
}
You will need to make HEAD request to fetch headers. Here is another simple version using fetch API could look like this:
getImgContentType (img) {
return fetch(img.src, { method: 'HEAD' })
.then(response => response.headers.get('Content-type'))
}
And usage would be:
obj.getImgContentType().then(type => {
console.log(type)
})
Also note, that getImgContentType's interface needs to be asynchronous. It's convenient to return promise.
Using a XMLHttpRequest of type HEAD (type HEAD means that the request will only recieve the header data, the image won't be redownloaded):
getImgContentType(img) {
var xhr = new XMLHttpRequest();
xhr.open("HEAD", img.src, true);
xhr.onreadystatechange = function() {
if (this.readyState == this.DONE) {
console.log(xhr.getResponseHeader("Content-Type")); // type
console.log(xhr.getResponseHeader("Content-Length")); // size
// ...
}
};
xhr.send();
}
Just note that not all servers implement HEAD requests.
On a webpage, once images have been downloaded and rendered, I need to determine an image's file size (kb) within the browser context (so I could display that info on the page, just below the image)
The easiest way is probably with a HEAD request returning the Content-Length:
function fileSize(img, func) {
var xhr = new XMLHttpRequest();
xhr.open('HEAD', img.src, true);
xhr.onreadystatechange = function() {
if(xhr.readyState == 4 && xhr.status == 200) {
func(xhr.getResponseHeader('Content-Length'))
}
}
xhr.send()
}
Usage
fileSize(imgNode, function(size) {
// ...
})