How to upload an image to google drive using gapi and react

前端 未结 2 1861
长发绾君心
长发绾君心 2020-12-21 15:39

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

相关标签:
2条回答
  • 2020-12-21 16:13

    Modification points:

    • From your script, it seems that 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.
      • And please be careful the line breaks of the request body for multipart/form-data.
    • When you want to use 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.

    Modified script:

    From:
    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
    });
    
    • In the upload of Drive API, in the current stage, it seems that both multipart/form-data and multipart/related can be used.

    Note:

    • In this answer, it supposes that your access token can be used for uploading the file to Google Drive. Please be careful this.

    Reference:

    • Upload file data

    Added:

    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) });
    

    Modification points:

    • At Drive API v3, the property for setting the filename is name.
    • uploadType=multipart is required to be used in the endpoint.
    • The base64 data is required to be converted to the blob.
      • For this, I referred this answer.

    When above points are reflected to your script, it becomes as follows.

    Sample script:

    // 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) });
    
    0 讨论(0)
  • 2020-12-21 16:34

    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.

    0 讨论(0)
提交回复
热议问题