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

2023-12-23

我正在使用 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 using

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

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

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

Notes:

  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”

有任何想法吗?


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


您将需要 Drive API

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

适用于浏览器 JavaScript 的 Drive 快速入门 https://developers.google.com/drive/api/v3/quickstart/js

流程可能是:

  • 让用户选择文件
  • 获取元数据对象
  • 从对象中提取文件ID
  • 调用 Drive API (get https://developers.google.com/drive/api/v3/reference/files/get with alt='media')

如果我误解了,并且您已经在使用 Drive API,那么查看相关代码将会很有帮助。

Ref

  • 快速开始 https://developers.google.com/drive/api/v3/quickstart/js
  • get https://developers.google.com/drive/api/v3/reference/files/get
  • export https://developers.google.com/drive/api/v3/reference/files/export)

EDIT:

以下是使用 Picker API 向 Drive API 提供信息的示例gapi使用相同的登录客户端。

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 ^^^^
}

此代码改编自驱动器快速入门 https://developers.google.com/drive/api/v3/quickstart/js选择器快速入门 https://developers.google.com/picker/docs.

Note- 这确实会在控制台中给出错误,但它似乎确实可以正常工作。这似乎确实是选择器的一个错误 -https://issuetracker.google.com/177046274 https://issuetracker.google.com/177046274

加布里埃尔编辑
Note- 使用 get withalt = media适用于二进制文件。要获取表格/文档/幻灯片等,您需要使用export终点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • 为服务/数据/缓存部署多个实例的好处

    尽管我有很多编写代码的经验 我真的没有太多部署经验 我正在编写一个项目 使用 mongodb 进行持久化 使用 redis 进行元缓存 并使用 play 来提供页面服务 我正在决定是否购买专用服务器 还是从 amazon linode 购买
  • 在 WebViewClient 中启用通用 JavaScript

    在谷歌搜索答案时 似乎我并不是唯一一个遇到似乎无法解决的问题的人 我成功地使用自定义 WebViewClient 创建了一个 WebView 这使得我可以拥有一个进程对话框 并在无法加载 URL 时显示错误消息 但这会给 JavaScrip
  • 出现错误 #1221 - UNION 和 LIMIT 的使用不正确

    我正在尝试使用这两个查询进行联合查询union在查询之间但出现错误 121 UNION 和 LIMIT 的使用不正确 请帮助我进行联合查询以获得这两个查询的结果 query1 SELECT t1 TraineeID t2 attnDate
  • 无需事务即可获取数据

    下面是 spring transaction 的示例代码片段 我的问题 相同的会话将用于获取第 1 行和第 2 行的实体吗 我的理解 我相信是的 这将由春季交易来保证 Transactional public void method1 fe
  • 如何为 f.select 表单字段设置空白值

    我使用以下内容允许我的用户在他们的个人资料中选择他们的性别 如果没有任何内容传递到 user sex 列 我将如何创建列表默认的空白值 我只是将男性或女性作为字符串传递 目的是我想要一个空白值 以便验证可以确保他们知道必须选择它 有两种可能
  • MySQL 获取两个用户之间的对话

    我有一个名为 private messages 的 SQL 表 其中包含字段 id from to message stamp 标记字段对应于消息的日期 那么我需要什么查询 1 获取两个用户之间的对话 按日期排序 我已经尝试过查询 SELE
  • Hive 中的 Presto UNNEST 函数相当于什么

    急板有一个UNNEST函数分解由数组组成的列 Hive 有类似的吗 请参阅文档UNNEST急速功能here https prestodb io docs current sql select html Use lateral view ou
  • 使用 DTO 时,Automapper 和 Nhibernate 反映正在更新的域对象中 DTO 子集合的更改

    我对这个设计不是很熟悉 但我希望得到一些指导 我有一个后端服务 它将 DTO 发送到 WPF 智能客户端 在 WPF 智能客户端上 用户将更改 删除和修改项目 然后将更改发送回 客户端 gt 服务器 举个例子 目前我正在处理客户详细信息表单
  • 无法让 dokka 在 gradle/android 项目上生成 kotlin 文档

    我正在关注 gradle 插件部分https github com Kotlin dokka https github com Kotlin dokka 我还尝试了 dokka gradle example 中的示例https github
  • Spring结果集提取器

    如何使用ResultSetExtractor从数据库检索数据 这里我使用oracle 10g作为后端 如果从员工表中搜索员工详细信息 哪个更好ResultSetExtractor or RowMapper 从 java 8 开始 还可以使用
  • 无继承的 OOP 重用:这在“现实世界”中有多实用?

    本文描述了一种我觉得很有趣的 OOP 方法 如果对象存在为 封装和通信 通过消息 如果代码重用了怎么办 与继承无关 但是 使用组合 委托 甚至 老式的辅助对象或任何 程序员认为合适的技术 本体并没有消失 但它 与实现分离 最令我震惊的是无需
  • 如何使用 Spring 的 JDBCTemplate 有效执行 IN() SQL 查询?

    我想知道是否有一种更优雅的方法来使用 Spring 的 JDBCTemplate 进行 IN 查询 目前我正在做类似的事情 StringBuilder jobTypeInClauseBuilder new StringBuilder for
  • JavaFX 没有 TouchEvents

    在我的 Windows Surface Go 2 平板电脑上 我无法检索任何 多点触控 触摸事件 我尝试了几个 Java FX 版本 即使使用 JavaFX 17 及更早版本 也不会生成 TouchEvents 事件 仅生成鼠标事件 是否需
  • 每10秒自我更新一次的小部件Handler.postDelayed问题

    我正在尝试使工作成为 Android 小部件中的自我更新功能 就像每 10 秒更改它的两个 TextView 一样简单 理想的解决方案是使其类似于精灵小部件 新闻和天气 到目前为止 它工作正常 它通过 Handler postDelayed
  • Pycharm 设置 Mysql 数据库驱动程序

    我正在尝试在 pycharm 中设置 mysql 数据库连接 我已经创建了架构并且它可以在 django 等中工作 我试图将数据源直接导入到 pycharm 但出现以下错误 Connection to Exception in thread
  • 为什么 smartcast 不能处理这种情况?

    我有一些与此结构类似的代码 private fun test Double val a Double 15 0 val b Double 20 0 return if a null b null 0 else if a null b nul
  • 我的主函数反汇编中所有这些奇怪的汇编指令是什么?

    所以我有这个主要功能 它会产生很多奇怪的指令 我使用的是 Visual Studio 2019 并且处于调试模式 因此禁用了优化 这些指令是做什么的 int main 00D340E0 push ebp 00D340E1 mov ebp e
  • 使用自定义 Comparer 的 OrderBy 的 Linq 语法

    对于带有自定义排序比较器的任何给定 Linq 表达式 有两种格式 Format 1 var query source Select x gt new x someProperty x otherProperty OrderBy x gt x
  • jQuery fadeIn '慢' 立即出现

    我试图做到这一点 以便当您单击链接时 它会删除一个 div 带有一些段落和文本 并插入另一个 div 带有一些段落和一些文本 我正在使用 jQuery 来淡入和淡出它们 当您单击链接时 原始 div 会淡出 然后我有一个 switch ca
  • 如何从 GooglePicker 上选定的文件中获取 blob

    我正在使用 GooglePicker 和 React 我得到的结果是一个对象数组 id 1 m serviceId docs mimeType image jpeg name name jpg description type photo