Get file from Google Drive and covert to Blob - javascript

I use function from this Google API JS sample
function downloadFile(file, callback) {
if (file.downloadUrl) {
var accessToken = gapi.auth.getToken().access_token;
var xhr = new XMLHttpRequest();
xhr.open('GET', file.downloadUrl);
xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
xhr.onload = function() {
callback(xhr.responseText);
};
xhr.onerror = function() {
callback(null);
};
xhr.send();
} else {
callback(null);
}
}
I get file content, but how i can create Blob from xhr.responseText ?

I found answer here http://www.html5rocks.com/ru/tutorials/file/xhr2/
I had to use
xhr.responseType='blob'

Try to use native Blob constructor.
Example form MDN:
var aFileParts = ['<a id="a"><b id="b">hey!</b></a>'];
var oMyBlob = new Blob(aFileParts, {type : 'text/html'}); // the blob

Related

how to retrieve text from google drive documents [duplicate]

This question already has answers here:
get file content of google docs using google drive API v3
(3 answers)
Closed 11 months ago.
I am using react-google-drive-picker to select a file from GDrive in my NextJS app. Once I have picked a file and retrieved the meta information, what is the suggested way to download or just retrieve the file content? What API is suggested to use authResponse to authenticate?
I am using:
useEffect(() => {
// do anything with the selected/uploaded files
if (data) {
var file = data.docs[0]
var xhr = new XMLHttpRequest();
xhr.open('GET', file['url']);
xhr.setRequestHeader('Authorization', 'Bearer ' + authResponse['access_token']);
xhr.setRequestHeader('Content-Type', 'application/vnd.google-apps.document');
xhr.onload = function () {
var content = xhr.responseText
console.log(content)
};
xhr.onerror = function () {
console.log("ERROR LOADING THE FILE")
};
xhr.send(JSON.stringify({"alt" : "media"}));
}
}, [data])
but the text of the document is not present in the response...
following the suggestion by #Gonzalo-Matheu, here's a way to obtain the text after picking a file with react-google-drive-picker in nextjs:
var file = data.docs[0]
var xhr = new XMLHttpRequest();
var url = 'https://www.googleapis.com/drive/v3/files/' + file['id'] + '/export?mimeType=text%2Fplain&key=' + process.env.NEXT_PUBLIC_GOOGLE_API_KEY
xhr.open('GET', URL);
xhr.setRequestHeader('Authorization', 'Bearer ' + authResponse['access_token']);
xhr.onload = function () {
var value = xhr.responseText
// do what you need with file content
console.log(value)
};
xhr.onerror = function () {
console.log("ERROR LOADING THE FILE")
};
xhr.send();

URL.createObjectURL(blob);

I am creating a PDF and opening in a new browser. My issue is word 'blob:' is getting appended to the URL
blob:http://localhost:3000/a0b859c9-57a0-40b7-a60f-9d2a72ab3c14
and I would like to be 'http://localhost:3000/a0b859c9-57a0-40b7-a60f-9d2a72ab3c14'
Is there a way I could achieve this ? My code is below
const blob = new Blob([response.data], {type : 'application/pdf'});
var pdfFileUrl = URL.createObjectURL(blob);
window.open(pdfFileUrl);
URL.revokeObjectURL(pdfFileUrl);
update:
I tried below code as well. It also gives the same results.
''
const xhr = new XMLHttpRequest();
//Send the proper header information along with the request
// listen for `onload` event
xhr.onload = () => {
// process response
if (xhr.status == 200) {
// parse JSON data
// console.log( "Response Received")
// var pdfurl = URL.createObjectURL(xhr.response) ;
console.log(xhr.response)
window.open(URL.createObjectURL(xhr.response));
} else {
console.log(" In Error block")
console.error('Error!');
}
};
// create a `GET` request
xhr.open('POST', url);
xhr.responseType = 'blob'
xhr.setRequestHeader('Content-Type', 'application/json');
// send request
xhr.send(JSON.stringify(payload));''

Download a file using XHR in iOS Safari

I am trying to add the functionality to download a file hosted in a server. To access the file I have to send the Authorization header, thus I have to send an XHR request to get the file from the server. Since the file content is in a variable, I have to create a data url to make it available as the href attribute of an anchor tag and click it programmatically to download the file.
It's working good in almost all the browser (Except IE11, for which I have written a separate code), but in iOS Safari (in some versions of iOS), it's giving errors. Here's the code that I am using -
var isBrowserIE = window.navigator && window.navigator.msSaveOrOpenBlob;
var dataHref = 'https://example.com/doc.pdf';
var xhr = new XMLHttpRequest();
xhr.open('GET', dataHref, true);
xhr.setRequestHeader('Content-Type', 'application/pdf');
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
xhr.responseType = isBrowserIE ? 'blob' : 'arraybuffer';
xhr.onload = function (e) {
if (this.status == 200) {
//For IE11
if (isBrowserIE) {
// Create a new Blob object using the response data of the onload object
var blob = new Blob([this.response], { type: 'application/pdf' });
var bool = window.navigator.msSaveOrOpenBlob(blob, docName);
if (!bool) {
alert("Download failed, Please try again later");
}
} else {
var uInt8Array = new Uint8Array(this.response);
var i = uInt8Array.length;
var binaryString = new Array(i);
while (i--) {
binaryString[i] = String.fromCharCode(uInt8Array[i]);
}
var data = binaryString.join('');
var base64 = window.btoa(data);
var dataUrl = 'data:application/octet-stream;charset=utf-16le;base64,' + base64;
var element = document.createElement('a');
element.setAttribute('href', dataUrl);
element.setAttribute('download', 'doc.pdf');
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
} else {
alert("Download failed, Please try again later");
closeWindow();
}
};
xhr.send();
Here's the possible error I am getting which is related -
Safari cannot open the page.<br><br>The error was: “Data URL decoding failed”.
Is there anything I missed which is the reason for this error? The error is occuring only in iPad 4 and iPad 5, but working in iPad mini and iPhone XR. Not sure why is it working in some versions of iOS devices and not in others.
So, I finally figured it out. Here's my final code with explanations in comments (Sorry for ES5 code, I needed to support IE11 and the current project is not using babel yet) -
/* exported DownloadHandler */
/* global Uint8Array*/
var DownloadHandler = (function() {
function isMobileDevice() {
return navigator.userAgent.match(/Android|iPhone|iPad|iPod|BlackBerry|Opera Mini|IEMobile/i);
}
function isChromeBrowser() {
return navigator.userAgent.match(/Crios|Chrome/i);
}
function isIEBrowser() {
return window.navigator && window.navigator.msSaveOrOpenBlob;
}
function isSafariBrowser() {
return navigator.userAgent.match(/Safari/i);
}
function getResponseType() {
// Both Desktop Chrome and IE supports blob properly
// Chrome also supports Data URI way, but it fails miserably when the file size is more than 2 MB (Not sure about the exact limit though).
if (isIEBrowser() || isChromeBrowser()) {
return 'blob';
} else if (isMobileDevice()) {
return 'arraybuffer';
}
return 'blob';
}
function getBlobUriFromResponse(response) {
var blob = new Blob([response], { type: 'application/pdf' });
var downloadUrl = URL.createObjectURL(blob);
return downloadUrl;
}
function getDataUriFromResponse(response) {
var uInt8Array = new Uint8Array(response);
var i = uInt8Array.length;
var binaryString = new Array(i);
while (i--) {
binaryString[i] = String.fromCharCode(uInt8Array[i]);
}
var data = binaryString.join('');
var base64 = window.btoa(data);
var dataUrl = 'data:application/octet-stream;charset=utf-16le;base64,' + base64;
return dataUrl;
}
function downloadFileUsingXHR(fileName, fileUrl, fileMimeType, requestType, headersList) {
var xhr = new XMLHttpRequest();
xhr.open(requestType, fileUrl, true);
xhr.setRequestHeader('Content-Type', fileMimeType);
for (var i = 0; i < headersList.length; i++) {
var header = headersList[i];
xhr.setRequestHeader(header.key, header.value);
}
xhr.responseType = getResponseType();
xhr.onload = function() {
if (this.status == 200) {
//For IE11
//IE uses blob with vendor specific code
if (isIEBrowser()) {
// Create a new Blob object using the response data of the onload object
var blob = new Blob([this.response], { type: fileMimeType });
var bool = window.navigator.msSaveOrOpenBlob(blob, fileName);
if (!bool) {
alert('Download failed, Please try again later');
}
} else {
var dataUrl;
if (this.responseType === 'blob') {
dataUrl = getBlobUriFromResponse(this.response);
} else {
dataUrl = getDataUriFromResponse(this.response);
}
var element = document.createElement('a');
// Safari doesn't work well with blank targets
if (!isSafariBrowser()) {
element.setAttribute('target', '_blank');
}
element.setAttribute('href', dataUrl);
element.setAttribute('download', fileName);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
} else {
alert('Download failed, Please try again later');
}
};
xhr.send();
}
return {
downloadFileUsingXHR: downloadFileUsingXHR
};
})();
Here's how to use the above code:
DownloadHandler.downloadFileUsingXHR('example.pdf', 'https://example.com/doc.pdf', 'application/pdf','GET',[{key:'Authorization',value:'Bearer ' + token}]);
I'll probably convert it into a library later and post a link here. I'll get the chance to refine the code too

node js XMLHttpRequest issue

Trying to run this in node js, code is constant throwing error on "xhr.target.status" of function makeCORRequest as if its not inheriting XMLHttpRequest functions for xhr. Code is for discord bot trying to get it to post from teamup calendar.
first function is working (and is where xhr is initialised) and is called by error function.
var logger = require('winston');
var auth = require('./auth.json');
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
function createCORSRequest(method, url) {
var apiKey = 'API_KEY';
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// XHR for Chrome/Firefox/Opera/Safari/IE10+.
xhr.open(method, url, true);
xhr.setRequestHeader('Teamup-Token', apiKey);
} else if (typeof XDomainRequest != "undefined") {
// XDomainRequest for IE8/IE9.
xhr = new XDomainRequest();
// XDomainRequest does not support querying HTTPS from HTTP pages
if (window.location.protocol === 'http:') {
url = url.replace('https://', 'http://');
}
if (-1 === ['GET', 'POST'].indexOf(method)) {
alert('XDomainRequest only supports GET and POST methods');
return;
}
if (-1 === url.indexOf('?')) {
url += '?_teamup_token=' + apiKey;
} else {
url += '&_teamup_token=' + apiKey;
}
xhr.open(method, url);
} else {
// CORS not supported.
xhr = null;
}
return xhr;
}
And this is the function that keeps failing. What works fine is xhr.onload =function(xhr), but if(xhr.target.status<400) throws the error "cannot read property"
// Sends the actual CORS request.
function makeCorsRequest(url, successCallback, errorCallback) {
var xhr = createCORSRequest('GET', url);
if (!xhr) {
alert('CORS not supported');
return;
}
// Response handlers.
xhr.onload = function (xhr) {
if (xhr.target.status < 400) {
if (successCallback) successCallback(xhr.target);
} else if (errorCallback) {
errorCallback(xhr.target);
}
};
xhr.onerror = function (xhr) {
if (errorCallback) {
errorCallback(xhr.target);
}
};
xhr.send();
}

XDomainRequest open("get", url) gives Access Denied error in IE

I'm using following code in one of my JavaScript file.
xhr = new XMLHttpRequest();
xhr.open("GET", dest, true); // dest is the URL
xhr.onreadystatechange = checkData;
xhr.send(null);
But when I run the script in IE,m it is giving me following error.
SCRIPT5: Access is denied.
Then I thought to check the browser type and execute a separate code for IE like below.
if(isIE){
xhr = new XDomainRequest();
xhr.onerror = function (res) { alert("error: " + res); };
xhr.ontimeout = function (res) { alert("timeout: " + res); };
xhr.onprogress = function (res) { alert("on progress: " + res); };
xhr.onload = function (res) { alert("on load: " + res); };
xhr.timeout = 5000;
xhr.open("get", dest); // Error line
xhr.send(json);
}
But again it is giving me the same error where I have used following code
xhr.open("get", dest);
At the end I want to call checkData function like I have done below with other browsers.
xhr.onreadystatechange = checkData;
What have I missing there to get Access Denied error at the IE console?
Try below.. It worked for me in IE8 and IE9.
if ($.browser.msie && window.XDomainRequest) {
// Use Microsoft XDR
var xdr = new XDomainRequest();
xdr.open("get", serviceURL+'GetItem/50000');
xdr.onload = function() {
//parse response as JSON
var response1 = $.parseJSON(xdr.responseText);
if (response1 == null || typeof(response1) == 'undefined') {
var result = $.parseJSON(data.firstChild.textContent);
alert(result);
} else {
$(response1.ResultData).each(function(i, item) {
alert(item.BorrName.toString());
});
}
};
xdr.send();
xdr.onerror = function(errormsg) {
alert('in error');
};
}
Service looks like below
[OperationContract]
[WebGet(UriTemplate = "GetItem/{itemnumber}", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
ItemEntity GetItem(string itemnumber);

Categories

Resources