I\'m trying to upload an image to google drive. I followed this tutorial for uploading files, I can upload a simple file but when I try to upload an image I get a corrupted
this.state.body
is the base64 data. In this case, it is required to add Content-Transfer-Encoding: base64
to the header of data in the request body.
multipart/form-data
.uploadType=multipart
, please set multipart/form-data; boundary=###
to the header as the content type. In your script, it seems that the content type is image/png
.When above points are reflected to your script, it becomes as follows.
const boundary = '-------314159265358979323846';
const delimiter = "\r\n--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
var fileName='mychat123.png';
var contentType='image/png'
var metadata = {
'name': fileName,
'mimeType': contentType
};
var multipartRequestBody =
delimiter + 'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) +
delimiter +
'Content-Type: ' + contentType + '\r\n';
multipartRequestBody += + '\r\n' + this.state.body;
multipartRequestBody += close_delim;
console.log(multipartRequestBody);
var request = window.gapi.client.request({
'path': 'https://www.googleapis.com/upload/drive/v3/files',
'method': 'POST',
'params': {'uploadType': 'multipart'},
'headers': {
'Content-Type': contentType
},
'body': multipartRequestBody
});
To:
const boundary = '-------314159265358979323846';
const delimiter = "--" + boundary + "\r\n";
const close_delim = "\r\n--" + boundary + "--";
var fileName = 'mychat123.png';
var contentType = 'image/png';
var metadata = {'name': fileName,'mimeType': contentType};
var multipartRequestBody = delimiter +
'Content-Type: application/json\r\n\r\n' +
JSON.stringify(metadata) + "\r\n" +
delimiter +
'Content-Type: ' + contentType + '\r\n' +
'Content-Transfer-Encoding: base64\r\n\r\n' +
this.state.body +
close_delim;
console.log(multipartRequestBody);
var request = window.gapi.client.request({
'path': 'https://www.googleapis.com/upload/drive/v3/files',
'method': 'POST',
'params': {'uploadType': 'multipart'},
'headers': {'Content-Type': 'multipart/form-data; boundary=' + boundary},
'body': multipartRequestBody
});
multipart/form-data
and multipart/related
can be used.From your replying, I noticed that you wanted to use fetch
instead of gapi.client.request
. In this case, the sample script is as follows.
This is your script in your comment.
const fd = new FormData();
fd.append("file", this.state.body);
fd.append("title", 'test.png');
const options = {
method: 'POST',
headers: { Authorization: "Bearer" + " " + window.gapi.auth.getToken().access_token },
body: fd
};
await fetch("googleapis.com/upload/drive/v3/files", options)
.then(response => response.json())
.then(jsonResp => { console.log(jsonResp) });
name
.uploadType=multipart
is required to be used in the endpoint.When above points are reflected to your script, it becomes as follows.
// Reference: https://stackoverflow.com/a/16245768
// This method converts from base64 data to blob.
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
const metadata = {name: 'test.png'};
const fd = new FormData();
fd.append('metadata', new Blob([JSON.stringify(metadata)], {type: 'application/json'}));
fd.append('file', b64toBlob(this.state.body, "image/png"));
fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart', {
method: 'POST',
headers: {Authorization: 'Bearer ' + window.gapi.auth.getToken().access_token},
body: fd
})
.then(response => response.json())
.then(jsonResp => { console.log(jsonResp) });
I created a customization on top of react-uploady, called drive-uploady that makes it trivial to upload to google drive with all the power of Uploady: hooks, UI components, progress, etc.
for example:
import React from "react";
import DriveUploady from "drive-uploady";
import UploadButton from "@rpldy/upload-button";
export const App = () => {
return <DriveUploady
clientId="<my-client-id>"
scope="https://www.googleapis.com/auth/drive.file"
>
<UploadButton>Upload to Drive</UploadButton>
</DriveUploady>;
};
Is all you need to render an upload button that logs in the user to Drive and uploads.