Angular 2+ HTTP POST 和 GDrive API.带名称的可恢复文件上传

我正在尝试将文件上传到 Angular 2 中的 Google Drive.到目前为止,我可以上传文件,但没有 title 并且它们是无标题"

I am trying to upload files to Google Drive in Angular 2. So far I am able to upload files, but without title and they are "Untitled"

这是执行此操作的代码:

Here is code to do that:

gDriveUploader(file): Promise<any> {
let authToken = tokenHere;
const url = `https://www.googleapis.com/upload/drive/v2/files/`
    let formData:FormData = new FormData();
    formData.append('title', file, file.name);
    let headers = new Headers({
      'Authorization': 'Bearer ' + authToken
    });
    headers.append('Accept', file.type);
    let options = new RequestOptions ({ 
      headers: headers,
    });

    console.log('OPTIONS: ', options)

    return this.http.post(`${url}`, formData, options)
        .toPromise()
           .then(response => response.json())
           .catch(e=>console.log(e));
}

我知道,为了发送带有文件的元数据,我必须将此元数据添加到 Request 正文并在 multipartresumable 上传类型.但是在这里我遇到了一个又一个问题,只是无法正常解决.

I know, that in order to send metadata with file, I have to add this metadata to Request body and use at multipart or resumable upload types. But here I faced issue after issue and just can't make it properly.

我完全搞砸了.这是我使用 resumable 上传类型的方法:

I completely messed up. Here is on of my approaches with resumable upload type:

gDriveUploader(file): Promise<any> {
let authToken = token;
const url = `https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable`
    console.log('FILE TO UPLOAD: ', file)
    let formData:FormData = new FormData();
    formData.append('name', file, file.name);
    let headers = new Headers({
      'Authorization': 'Bearer ' + authToken,
      'Content-Type': 'application/json; charset=UTF-8', //if remove "Bad Content" Error
      //'Content-Length': file.size, not sure if this one right?
    });
    let options = new RequestOptions ({ 
      headers: headers,
    });

    return this.http.post(`${url}`, formData, options)
        .toPromise()
           .then(response => response.json())
           .catch(e=>console.log(e));
}

这不仅仅是我的两种方法......

that's not only two of my approaches...

根据 Drive API for resumable 上传:

According to Drive API for resumable upload:

POST https://www.googleapis.com/drive/v3/files?uploadType=resumable 

HTTP/1.1
Authorization: Bearer [YOUR_AUTH_TOKEN]
Content-Length: 38
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Type: image/jpeg
X-Upload-Content-Length: 2000000

什么是Content-Length: 38?这是文件长度,我可以使用 file.size?

What is Content-Length: 38? it's file length and I can just use file.size?

使用 multipart 我无法弄清楚如何在请求中添加那些边界分隔符.

With multipart I can't figure out how to add those boundary separator in the request.

我看到了一些问答,Angular 不支持 multipart,但那是 1-2 年前的事了.现在呢?

I saw some Q and A, that multipart were not supported by Angular, but that was 1-2 year ago. What about now?

我可以使用标准 Angular 功能以某种方式使用可恢复上传到 GDrive 以及其他文件元数据吗?

Can I somehow use resumable upload to GDrive with additional file metadata using standard Angular features?

推荐答案

所以.关于 API 工作原理的更多研究.我想出了以下可恢复文件上传的解决方案.主要思想,第一次我必须为我的文件发出请求并设置元数据"并通过链接获得响应,上传文件的位置.这个链接作为 response header 之一出现,称为 location.

So. A bit more research on how API works. I came up with the following solution for resumable file upload. Main Idea, that first time I have to make a request and "set metadata" for my file and get response with the link, where to upload the file. And this link came as one of the response header called location.

这是完整的工作代码.只需将 File 对象传递给第一个函数.

Here is fully working code. Just pass File object to the first function.

我只是很快为此制作了 2 个函数.第一个将设置元数据(只是名称)并调用第二个函数来上传二进制数据.

I just quickly made 2 functions for this. First one will set metadata (just name) and call second function to upload just binary data.

gDriveUploader(file): Promise<any> {
  let authToken = token
  const url = `https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable`
      let headers = new Headers({
        'Authorization': 'Bearer ' + authToken,
        'Content-Type': 'application/json; charset=UTF-8',
      });
      let options = new RequestOptions ({ 
        headers: headers,
      });
      return this.http.post(`${url}`, {name: file.fullName}, options) //just set the name
          .toPromise()
            .then(response => this.gDriveUploadFile(file, response.headers.get('location'))) //call second function to upload `file` to proper URI from response
            .then(response => {
                let id = response.json().id //parse id of uploaded file
                let resp = {fileName: file.fullName, fileType: file.fileType, fileSize: file.size, fileId: id} //create an object with file file properties, if you need that
                return resp // return object back to function that called this service
            })
            .catch(e=>console.log(e));
  }

上传数据的第二个函数:

Second function to upload data:

gDriveUploadFile(file, url): Promise<any> { //file and url we got from first func
  let authToken = token
      let headers = new Headers({
        'Authorization': 'Bearer ' + authToken,
        'Content-Type': 'application/json; charset=UTF-8',
        'X-Upload-Content-Type': file.type
      });
      let options = new RequestOptions ({ 
        headers: headers,
      });
      return this.http.post(`${url}`, file, options) //call proper resumable upload endpoint and pass just file as body
          .toPromise()
  }

可能解决方案不理想,目前我这里没有处理错误,也没有使用分块上传等resumable特性,只需要一次上传文件.但希望如果其他人坚持 GDrive 上传可以得到一个想法.

Maybe solution not ideal, so far I do not handle errors here and do not use resumable features like uploading by chunks, just upload file at once. But hopefully if someone else stuck with GDrive uploading can get an idea.

相关文章