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

javascript - How to upload files to Google drive using gapi and resumable uploads? - Stack Overflow

programmeradmin0浏览0评论

I'm trying to follow this guide for doing resumable uploads on Google Drive through Google Api's.

This is my code, you can see it makes 2 requests as the guide asks to, the first part creates the metadata, and then we use the location for starting uploading the files with the session created by the first request.

        const file = new File(['Hello, world!'], 'hello world.txt', { type: 'text/plain;charset=utf-8' });
        const contentType = file.type || 'application/octet-stream';

        const reqMetadata = gapi.client.request({
            'path': 'upload/drive/v3/files',
            'method': 'POST',
            'params': { 'uploadType': 'resumable' },
            'headers': {
                'X-Upload-Content-Type': file.type,
                'X-Upload-Content-Length': file.size,
                'Content-Type': 'application/json; charset=UTF-8'
            },
            'body': {
                'name': file.name,
                'mimeType': contentType,
                'Content-Type': contentType,
                'Content-Length': file.size
            }
        });

        reqMetadata.execute((respMetadata, rawRespMetadata: any) => {
            const locationUrl = JSON.parse(rawRespMetadata).gapiRequest.data.headers.location;

            const reader = new FileReader();

            reader.onload = (e) => {
                const reqFile = gapi.client.request({
                    'path': locationUrl,
                    'method': 'PUT',
                    'headers': {
                        'Content-Type': file.type,
                        'Content-Length': file.size
                    },
                    'body': reader.result
                });

                reqFile.execute(respFile => {
                    console.log(respFile);
                });
            };

            reader.readAsArrayBuffer(file);
        });

What's the problem?

Well, seems that the Google Api library does not like the File / byte array as body on their gapi.client.request and they're truncating it away

What's the correct way to pass the file? I tried both body: file and body: reader.result but same result

PS: gapi is already fully authenticated & initialized with auth2, I'm able to create files / directory.

EDIT 1:

gapi library is just jsoing the FileArray, therefore the JSON function modifies it to a empty object, no way to make it work.. something must be missing.

EDIT 2:

I made it work without the GAPI, it correctly uploads the file but I have some issues with the CORS

            reader.onload = (e) => {                    

                const authHeader = `Bearer ${this.auth.currentUser.get().getAuthResponse().access_token}`;
                const headers = new Headers({
                    'Authorization': authHeader,
                    'Content-Type': file.type
                });
                const options = new RequestOptions({ headers });
                const url = locationUrl;

                this.http.put(url, reader.result, options).subscribe(res => {
                    observer.next(res);
                }, (err) => {
                    observer.next({});
                });
            };

            reader.readAsArrayBuffer(file);

If somebody has some hints..

I'm trying to follow this guide for doing resumable uploads on Google Drive through Google Api's.

This is my code, you can see it makes 2 requests as the guide asks to, the first part creates the metadata, and then we use the location for starting uploading the files with the session created by the first request.

        const file = new File(['Hello, world!'], 'hello world.txt', { type: 'text/plain;charset=utf-8' });
        const contentType = file.type || 'application/octet-stream';

        const reqMetadata = gapi.client.request({
            'path': 'upload/drive/v3/files',
            'method': 'POST',
            'params': { 'uploadType': 'resumable' },
            'headers': {
                'X-Upload-Content-Type': file.type,
                'X-Upload-Content-Length': file.size,
                'Content-Type': 'application/json; charset=UTF-8'
            },
            'body': {
                'name': file.name,
                'mimeType': contentType,
                'Content-Type': contentType,
                'Content-Length': file.size
            }
        });

        reqMetadata.execute((respMetadata, rawRespMetadata: any) => {
            const locationUrl = JSON.parse(rawRespMetadata).gapiRequest.data.headers.location;

            const reader = new FileReader();

            reader.onload = (e) => {
                const reqFile = gapi.client.request({
                    'path': locationUrl,
                    'method': 'PUT',
                    'headers': {
                        'Content-Type': file.type,
                        'Content-Length': file.size
                    },
                    'body': reader.result
                });

                reqFile.execute(respFile => {
                    console.log(respFile);
                });
            };

            reader.readAsArrayBuffer(file);
        });

What's the problem?

Well, seems that the Google Api library does not like the File / byte array as body on their gapi.client.request and they're truncating it away

What's the correct way to pass the file? I tried both body: file and body: reader.result but same result

PS: gapi is already fully authenticated & initialized with auth2, I'm able to create files / directory.

EDIT 1:

gapi library is just jsoing the FileArray, therefore the JSON function modifies it to a empty object, no way to make it work.. something must be missing.

EDIT 2:

I made it work without the GAPI, it correctly uploads the file but I have some issues with the CORS

            reader.onload = (e) => {                    

                const authHeader = `Bearer ${this.auth.currentUser.get().getAuthResponse().access_token}`;
                const headers = new Headers({
                    'Authorization': authHeader,
                    'Content-Type': file.type
                });
                const options = new RequestOptions({ headers });
                const url = locationUrl;

                this.http.put(url, reader.result, options).subscribe(res => {
                    observer.next(res);
                }, (err) => {
                    observer.next({});
                });
            };

            reader.readAsArrayBuffer(file);

If somebody has some hints..

Share Improve this question edited Sep 18, 2017 at 9:59 Luca Trazzi asked Sep 11, 2017 at 16:39 Luca TrazziLuca Trazzi 1,2601 gold badge13 silver badges32 bronze badges 6
  • What GAPI version are you using? Also, the GAPI seems to be using sreams for uploading ifles in NodeJS. You could try with this – Mathieu de Lorimier Commented Sep 18, 2017 at 19:26
  • Should be the latest version, where did you find documentation about the use of streams (sockets)? – Luca Trazzi Commented Sep 19, 2017 at 8:01
  • Here, look at the NodeJS examples. – Mathieu de Lorimier Commented Sep 19, 2017 at 12:26
  • I'm on the browser, can't use NodeJS streams. – Luca Trazzi Commented Sep 19, 2017 at 14:02
  • 1 Have you tried to send feedback about the issue developers.google./drive/v3/web/…? – guest271314 Commented Sep 20, 2017 at 0:10
 |  Show 1 more ment

2 Answers 2

Reset to default 6 +50

You must use XMLHttpRequest to make a cross origin HTTP request. The gapi client does not support XMLHttpRequest. (but there is this pull request that's been open for a while) Even though you aren't sending the file binary data in the initial request, you must use XMLHttpRequest for both the initial and the request where the file is uploaded in order for the returned location url provide the appropriate response header (Access-Control-Allow-Origin: YOUR_URL) and satisfy the CORS requirements.

Here is a great tutorial about CORS and XMLHttpRequest that may be useful in converting your requests.

You can use the request info described in the page you linked to. This example shows the request info but does not provide any info on getting the auth token. But this example does!

I was able to successfully upload the file using the following code:

const file = new File(['Hello, world!'], 'hello world.txt', { type: 'text/plain;charset=utf-8' });
const contentType = file.type || 'application/octet-stream';
const user = gapi.auth2.getAuthInstance().currentUser.get();
const oauthToken = user.getAuthResponse().access_token;
const initResumable = new XMLHttpRequest();
initResumable.open('POST', 'https://www.googleapis./upload/drive/v3/files?uploadType=resumable', true);
initResumable.setRequestHeader('Authorization', 'Bearer ' + oauthToken);
initResumable.setRequestHeader('Content-Type', 'application/json');
initResumable.setRequestHeader('X-Upload-Content-Length', file.size);
initResumable.setRequestHeader('X-Upload-Content-Type', contentType);
initResumable.onreadystatechange = function() {
  if(initResumable.readyState === XMLHttpRequest.DONE && initResumable.status === 200) {
    const locationUrl = initResumable.getResponseHeader('Location');
    const reader = new FileReader();
    reader.onload = (e) => {
      const uploadResumable = new XMLHttpRequest();
      uploadResumable.open('PUT', locationUrl, true);
      uploadResumable.setRequestHeader('Content-Type', contentType);
      uploadResumable.setRequestHeader('X-Upload-Content-Type', contentType);
      uploadResumable.onreadystatechange = function() {
        if(uploadResumable.readyState === XMLHttpRequest.DONE && uploadResumable.status === 200) {
          console.log(uploadResumable.response);
         }
      };
      uploadResumable.send(reader.result);
    };
    reader.readAsArrayBuffer(file);
  }
};

// You need to stringify the request body containing any file metadata

initResumable.send(JSON.stringify({
  'name': file.name,
  'mimeType': contentType,
  'Content-Type': contentType,
  'Content-Length': file.size
}));

But there is a more robust repo for dealing with all this here: https://github./googledrive/cors-upload-sample

This is the BMcV solution translated to angular http service.

const contentType = file.type || 'application/octet-stream';
const baseRoot = gapi['config'].get('googleapis.config').root;

const reader = new FileReader();

reader.onload = (e) => {

    const authHeader = `Bearer ${this.auth.currentUser.get().getAuthResponse().access_token}`;

    const metadataHeaders = {
        'Authorization': authHeader,
        'Content-Type': 'application/json',
        'X-Upload-Content-Length': file.size,
        'X-Upload-Content-Type': contentType
    };
    const metadataOptions = new RequestOptions({ headers: new Headers(metadataHeaders) });

    const url = `${baseRoot}/upload/drive/v3/files?uploadType=resumable`;

    const metadata = {
        'name': file.name,
        'mimeType': contentType,
        'Content-Type': contentType,
        'Content-Length': file.size
    };

    this.http.post(url, metadata, metadataOptions).subscribe(metadataRes => {

        const locationUrl = metadataRes.headers.get('Location');

        const uploadHeaders = {
            'Content-Type': contentType,
            'X-Upload-Content-Type': contentType
        };
        const uploadOptions = new RequestOptions({ headers: new Headers(uploadHeaders) });

        this.http.put(locationUrl, reader.result, uploadOptions).subscribe(uploadRes => {
            console.log(uploadRes.json());
        });
    }, (err) => {
        console.error(err);
    });
};
reader.readAsArrayBuffer(file);
发布评论

评论列表(0)

  1. 暂无评论