如何从 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);
});
});
但我得到 403
或 CORS
;我尝试在选择器中设置 relayUrl
,但这破坏了选择器。
备注:
- 我的 auth2 中有这 3 个范围:
['https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.readonly']```
- 我的计算机 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(
get
和 alt='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
端点。
我正在使用 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);
});
});
但我得到 403
或 CORS
;我尝试在选择器中设置 relayUrl
,但这破坏了选择器。
备注:
- 我的 auth2 中有这 3 个范围:
['https://www.googleapis.com/auth/drive.file', 'https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/drive.readonly']```
- 我的计算机 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(
get
和alt='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
端点。