如何从 GooglePicker 上的选定文件中获取 blob

How to get a blob from selected files on GooglePicker

我正在使用 GooglePicker 和 React,我得到的结果是一个对象数组...

[
  {
    "id": "1...m",
    "serviceId": "docs",
    "mimeType": "image/jpeg",
    "name": "name.jpg",
    "description": "",
    "type": "photo",
    "lastEditedUtc": 1575388407136,
    "iconUrl": "https://drive-thirdparty.googleusercontent.com/16/type/image/jpeg",
    "url": "https://drive.google.com/file/d/1...m/view?usp=drive_web",
    "embedUrl": "https://drive.google.com/file/d/1...m/preview?usp=drive_web",
    "sizeBytes": 111364,
    "rotation": 0,
    "rotationDegree": 0,
    "parentId": "0...A"
}]

所以我尝试通过 https://www.googleapis.com/drive/v3/files 访问并使用

直接通过 file.url 访问

const fetchOptions = { headers: { Authorization: `Bearer ${accessToken}` } };

docs.forEach((file) => {
  ...
  fetch(file.url, fetchOptions).then((res) => {
    const blob = res.blob();
    uploadFile(blob);
  });
});

但我得到 403CORS;我尝试在选择器中设置 relayUrl,但这破坏了选择器。

备注:

  1. 我的 auth2 中有这 3 个范围:
        ['https://www.googleapis.com/auth/drive.file',
        'https://www.googleapis.com/auth/drive',
        'https://www.googleapis.com/auth/drive.readonly']```
    
  2. 我的计算机 url 端口和协议设置为授权 JavaScript 来源和授权重定向 URI

有什么想法吗?


编辑 1:

我也试过这样使用 Google API:

const FILE_URL = 'https://www.googleapis.com/drive/v3/files';
const url = isDoc
        ? `${FILE_URL}/${file.id}/export?mimeType=${mimeType}`
        : `${FILE_URL}/${file.id}?alt=media`;

      fetch(url, fetchOptions).then((res) => {
        const blob = res.blob();
        uploadFile(blob);
      });

您将需要驱动器 API

从你的问题来看,你似乎正在尝试用 Google Picker 做所有事情。但是,选择器只会为您提供有限的文件元数据,因此您可以使用您的帐户打开它们(即在另一个 window 中查看它们)或让您上传文件。如果您想下载 实际文件,则需要使用驱动器API。

Drive Quickstart for browser JavaScript

流程可能是:

  • 让用户选择文件
  • 获取元数据对象
  • 从对象中提取文件 ID
  • 调用云端硬盘 API(getalt='media'

如果我误解了你已经在使用驱动器API,那么查看相关代码会很有帮助。

参考

编辑:

这里是一个使用选择器 API 与 gapi 使用相同的登录客户端将数据输入到驱动器 API 的示例。

HTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta charset="utf-8" />
    <title>Google Picker Example</title>
    
  </head>
  <body>
    <button id="authorize_button" style="display: none;">Authorize</button>
    <button id="signout_button" style="display: none;">Sign Out</button>
    <div id="result"></div>

    <script type="text/javascript" src="script.js"></script>
    <script async defer src="https://apis.google.com/js/api.js"
    onload="this.onload=function(){};handleClientLoad()"
    onreadystatechange="if (this.readyState === 'complete') this.onload()">
  </script>
  </body>
</html>

JS

const API_KEY = 'AI...';
const CLIENT_ID = '44...';
const appId = "44...";

const SCOPES = ["https://www.googleapis.com/auth/drive"];

const DISCOVERY_DOCS = [
  "https://www.googleapis.com/discovery/v1/apis/drive/v3/rest",
];

const authorizeButton = document.getElementById("authorize_button");
const signoutButton = document.getElementById("signout_button");

// Use the Google API Loader script to load the google.picker script.
function handleClientLoad() {
  gapi.load("client:auth2:picker", initClient);
}

function initClient() {
  gapi.client.init({
      apiKey: API_KEY,
      clientId: CLIENT_ID,
      discoveryDocs: DISCOVERY_DOCS,
      scope: SCOPES[0]
    })
    .then(
      function () {
        // Listen for sign-in state changes.
        gapi.auth2.getAuthInstance().isSignedIn.listen(handleSignIn);

        // Handle the initial sign-in state.
        handleSignIn(gapi.auth2.getAuthInstance().isSignedIn.get());
        authorizeButton.onclick = handleAuthClick;
        signoutButton.onclick = handleSignoutClick;
      },
      function (error) {
        appendPre(JSON.stringify(error, null, 2));
      }
    );
}

function handleSignIn(isSignedIn) {
  if (isSignedIn) {
    authorizeButton.style.display = "none";
    signoutButton.style.display = "block";
    createPicker();
  } else {
    authorizeButton.style.display = "block";
    signoutButton.style.display = "none";
  }
}

function handleAuthClick(event) {
  gapi.auth2.getAuthInstance().signIn();
}

function handleSignoutClick(event) {
  gapi.auth2.getAuthInstance().signOut();
}

function createPicker() {
  const token = gapi.client.getToken().access_token
  if (token) {
    
    let view = new google.picker.View(google.picker.ViewId.DOCS);
    view.setMimeTypes("image/png,image/jpeg,image/jpg");
    let picker = new google.picker.PickerBuilder()
      .enableFeature(google.picker.Feature.NAV_HIDDEN)
      .enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
      .setAppId(appId)
      .setOAuthToken(token)
      .addView(view)
      .addView(new google.picker.DocsUploadView())
      .setDeveloperKey(API_KEY)
      .setCallback(getFile)
      .build();
    picker.setVisible(true);
  }
}

function getFile(pickerResp) {
  gapi.client.drive.files
    .get({
      fileId: pickerResp.docs[0].id,
      alt: 'media'
    })
    .then(resp => {
      console.log("fetch response", resp.status)
      let binary = resp.body
      // EDIT - addition from Gabrielle vvvv
      let l = binary.length
      let array = new Uint8Array(l);
      for (var i = 0; i<l; i++){
        array[i] = binary,charCodeAt(i);
      }
      let blob = new Blob([array], {type: 'application/octet-stream'});
      // EDIT - addition from Gabrielle ^^^^
}

此代码改编自 Drive Quickstart and the Picker Quickstart

注意 - 这确实在控制台中给出了一个错误,但它似乎确实有效。这似乎是选择器的错误 - https://issuetracker.google.com/177046274

编辑加布里埃尔
注意 - 使用 get 和 alt = media 用于二进制文件。要获得 sheets/docs/slides 等,您需要使用 export 端点。