最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Google Drive API and file uploads from the browser - Stack Overflow

programmeradmin2浏览0评论

I'm trying to upload a file with the Google Drive api, and I have the metadata correct, and I want to ensure that the actual file contents make it there. I have a simple page setup that looks like this:

<div id="upload">
  <h6>File Upload Operations</h6>
  <input type="file" placeholder='file' name='fileToUpload'>
  <button id='uploadFile'>Upload File</button>
</div>

and I have a the javascript setup where the user is prompted to sign in first, and then they can upload a file. Here's the code: (currently only uploads the file metadata....)

let uploadButton = document.getElementById('uploadFile');
uploadButton.onclick = uploadFile;
const uploadFile = () => {
    let ftu = document.getElementsByName('fileToUpload')[0].files[0];
    console.dir(ftu);
    gapi.client.drive.files.create({
        'content-type': 'application/json;charset=utf-8',
        uploadType: 'multipart',
        name: ftu.name,
        mimeType: ftu.type,
        fields: 'id, name, kind'
    }).then(response => {
        console.dir(response);
        console.log(`File: ${ftu.name} with MimeType of: ${ftu.type}`);
        //Need code to upload the file contents......
    });
};

First, I'm more familiar with the back end, so getting the file in bits from the <input type='file'> tag is a bit nebulous for me. On the bright side, the metadata is there. How can I get the file contents up to the api?

I'm trying to upload a file with the Google Drive api, and I have the metadata correct, and I want to ensure that the actual file contents make it there. I have a simple page setup that looks like this:

<div id="upload">
  <h6>File Upload Operations</h6>
  <input type="file" placeholder='file' name='fileToUpload'>
  <button id='uploadFile'>Upload File</button>
</div>

and I have a the javascript setup where the user is prompted to sign in first, and then they can upload a file. Here's the code: (currently only uploads the file metadata....)

let uploadButton = document.getElementById('uploadFile');
uploadButton.onclick = uploadFile;
const uploadFile = () => {
    let ftu = document.getElementsByName('fileToUpload')[0].files[0];
    console.dir(ftu);
    gapi.client.drive.files.create({
        'content-type': 'application/json;charset=utf-8',
        uploadType: 'multipart',
        name: ftu.name,
        mimeType: ftu.type,
        fields: 'id, name, kind'
    }).then(response => {
        console.dir(response);
        console.log(`File: ${ftu.name} with MimeType of: ${ftu.type}`);
        //Need code to upload the file contents......
    });
};

First, I'm more familiar with the back end, so getting the file in bits from the <input type='file'> tag is a bit nebulous for me. On the bright side, the metadata is there. How can I get the file contents up to the api?

Share Improve this question asked Dec 18, 2018 at 19:01 Chris RutherfordChris Rutherford 1,6723 gold badges28 silver badges61 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 5

So According to some resources I've found in my three day search to get this going, the file simply cannot be uploaded via the gapi client. It must be uploaded through a true REST HTTP call. So let's use fetch!

const uploadFile = () => {
    //initialize file data from the dom
    let ftu = document.getElementsByName('fileToUpload')[0].files[0];
    let file = new Blob([ftu]); 
    //this is to ensure the file is in a format that can be understood by the API

    gapi.client.drive.files.create({
        'content-type': 'application/json',
        uploadType: 'multipart',
        name: ftu.name,
        mimeType: ftu.type,
        fields: 'id, name, kind, size'
    }).then(apiResponse => {
        fetch(`https://www.googleapis./upload/drive/v3/files/${response.result.id}`, {
         method: 'PATCH',
         headers: new Headers({
             'Authorization': `Bearer ${gapi.client.getToken().access_token}`,
              'Content-Type': ftu.type
         }),
         body: file
       }).then(res => console.log(res));

}

The Authorization Header is assigned from calling the gapi.client.getToken().access_token function, and basically this takes the empty object from the response on the gapi call and calls the fetch api to upload the actual bits of the file!

In your situation, when you upload a file using gapi.client.drive.files.create(), the empty file which has the uploaded metadata is created. If my understanding is correct, how about this workaround? I have experienced the same situation with you. At that time, I used this workaround.

Modification points:

  • Retrieve access token using gapi.
  • File is uploaded using XMLHttpRequest.

Modified script:

Please modify the script in uploadFile().

let ftu = document.getElementsByName('fileToUpload')[0].files[0];
var metadata = {
    'name': ftu.name,
    'mimeType': ftu.type,
};
var accessToken = gapi.auth.getToken().access_token; // Here gapi is used for retrieving the access token.
var form = new FormData();
form.append('metadata', new Blob([JSON.stringify(metadata)], {type: 'application/json'}));
form.append('file', ftu);

var xhr = new XMLHttpRequest();
xhr.open('post', 'https://www.googleapis./upload/drive/v3/files?uploadType=multipart&fields=id,name,kind');
xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
xhr.responseType = 'json';
xhr.onload = () => {
    console.log(xhr.response);
};
xhr.send(form);

Note:

  • In this modified script, it supposes that Drive API is enabled at API console and the access token can be used for uploading file.
  • About fields, you are using id,name,kind. So this sample also uses them.

Reference:

  • gapi

If I misunderstand your question or this workaround was not useful for your situation, I'm sorry.

Edit:

When you want to use fetch, how about this sample script?

let ftu = document.getElementsByName('fileToUpload')[0].files[0];
var metadata = {
    'name': ftu.name,
    'mimeType': ftu.type,
};
var accessToken = gapi.auth.getToken().access_token; // Here gapi is used for retrieving the access token.
var form = new FormData();
form.append('metadata', new Blob([JSON.stringify(metadata)], {type: 'application/json'}));
form.append('file', ftu);

fetch('https://www.googleapis./upload/drive/v3/files?uploadType=multipart&fields=id,name,kind', {
  method: 'POST',
  headers: new Headers({'Authorization': 'Bearer ' + accessToken}),
  body: form
}).then((res) => {
  return res.json();
}).then(function(val) {
  console.log(val);
});

With https://www.npmjs./package/@types/gapi.client.drive

const makeUploadUrl = (fileId: string, params: Record<string, boolean>) => {
  const uploadUrl = new URL(
    `https://www.googleapis./upload/drive/v3/files/${fileId}`
  )

  Object.entries({
    ...params,
    uploadType: 'media',
  }).map(([key, value]) => uploadUrl.searchParams.append(key, `${value}`))

  return uploadUrl
}


  const uploadDriveFile = async ({ file }: { file: File }) => {
    const params = {
      enforceSingleParent: true,
      supportsAllDrives: true,
    }
    
    // create file handle 
    const { result } = await gapi.client.drive.files.create(params, {
      // CAN'T have the upload type here!
      name: file.name,
      mimeType: file.type,
      // any resource params you need...
      driveId: process.env.DRIVE_ID,
      parents: [process.env.FOLDER_ID],
    })

    // post the file data
    await fetch(makeUploadUrl(result.id!, params), {
      method: 'PATCH',
      headers: new Headers({
        Authorization: `Bearer ${gapi.client.getToken().access_token}`,
        'Content-Type': file.type,
      }),
      body: file,
    })

    return result
  })
}
发布评论

评论列表(0)

  1. 暂无评论