Firebase Can';找不到使用RESTAPI上传到Google Drive的文件
我正在尝试使用RESTAPI和服务帐户将媒体文件上载到Google Drive。我有一个云函数后端,在那里我使用GoogleDrive API的正确作用域进行身份验证,并将访问令牌(如下面的代码段所示)返回给客户端,然后客户端可以向GoogleDrive发出上载请求Firebase Can';找不到使用RESTAPI上传到Google Drive的文件,firebase,react-native,google-drive-api,google-cloud-functions,expo,Firebase,React Native,Google Drive Api,Google Cloud Functions,Expo,我正在尝试使用RESTAPI和服务帐户将媒体文件上载到Google Drive。我有一个云函数后端,在那里我使用GoogleDrive API的正确作用域进行身份验证,并将访问令牌(如下面的代码段所示)返回给客户端,然后客户端可以向GoogleDrive发出上载请求 const auth = new google.auth.GoogleAuth({ scopes: [ 'https://www.googleapis.com/auth/cloud-platform',
const auth = new google.auth.GoogleAuth({
scopes: [
'https://www.googleapis.com/auth/cloud-platform',
'https://www.googleapis.com/auth/drive.appdata',
'https://www.googleapis.com/auth/drive'
]
});
const client = await auth.getClient();
return await client.getAccessToken();
这在网络上运行良好,甚至在世博快餐网站上也可以看到。现在,我需要在移动平台上使用React Native来实现这一点,但是每次我上传一个文件,我都会得到200个响应和文件id,但是我在指定的文件夹或Google Drive上的任何其他地方都找不到该文件。下面的代码片段只是我用来上传到web版本的相同逻辑的重写
import React, {useEffect, useState} from 'react'
import {View, Text, StyleSheet, Platform, Button, Image} from 'react-native'
import * as ImagePicker from 'expo-image-picker';
import axios from 'axios'
import {decode as atob} from 'base-64'
export const UploadToDrive = (props) => {
const [image, setImage] = useState(null);
const [uploadPercent, setUploadPercent] = useState(0)
const [mimeType, setMimeType] = useState('')
useEffect(() => {
(async () => {
if (Platform.OS !== 'web') {
const { status } = await ImagePicker.requestCameraRollPermissionsAsync();
if (status !== 'granted') {
alert('Sorry, we need camera roll permissions to make this work!');
}
}
})();
}, []);
const pickImage = async () => {
const baseURL = 'https://dummy-server-address/api';
// Simultaneously get the access token while picking the media
const [{response}, result] = await Promise.all([
fetch(
`${baseURL}/services/fetch-access-token`,
{
mode: "cors",
}
)
.then((res) => res.json())
.then((resp) => resp)
.catch((err) => console.log(err)),
ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
})
]).catch((err) => console.log(err))
// ensure that all needed parameters/fields are present
if (!result.cancelled && response.token) {
const accessToken = response.token
const uri = "file:///" + result.uri.split("file:/").join("");
setImage(uri);
const file = result
let filename = uri.split('/').pop();
let match = /\.(\w+)$/.exec(filename);
let type = match ? `image/${match[1]}` : `image`;
file.name = filename;
file.type = type
file.uri = uri
console.log(file)
setMimeType(file.type)
// Upload the image using the fetch and FormData APIs
let formData = new FormData();
const metadata = {
name: file.name,
type: file.type || 'multipart/form-data',
parents: ["1yz6MUU0YfXz0rl7TObq-JOPCmC6sHKdQ"],
};
// construct the file metadata for the upload
formData.append(
"metadata",
new Blob([JSON.stringify(metadata)], { type: "application/json" })
);
// formData.append('file', { uri, name: filename, type });
formData.append('file', file);
const url =
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id";
// let uploadPercent;
const upload_res = await axios(url, {
method: "POST",
headers: {
Authorization: "Bearer " + accessToken,
},
data: formData,
onUploadProgress: (p) => {
setUploadPercent((p.loaded / p.total) * 100)
},
})
.catch(err => console.log({err}))
.finally(() => setUploadPercent(0));
console.log({ data: upload_res.data });
} else {
throw new Error('You do not have all the right variables to make an upload')
}
};
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
{!!uploadPercent && <Text style={styles.uploadPercent}>Upload Percent: {`${uploadPercent.toFixed(2)}%`}</Text>}
<Button style={styles.button} title="Pick a file" onPress={pickImage} />
{image && mimeType.includes('image') && <Image source={{ uri: image }} style={{ width: 200, height: 200, marginTop: 20 }} />}
</View>
)
}
const styles = StyleSheet.create({
button: {
position: 'absolute',
top: '10%'
},
uploadPercent: {
color: 'tomato',
fontSize: 15,
fontWeight: 'bold',
marginBottom: 20
}
})
import React,{useffect,useState}来自“React”
从“react native”导入{视图、文本、样式表、平台、按钮、图像}
从“世博会图像采集器”导入*作为图像采集器;
从“axios”导入axios
从'base-64'导入{decode as atob}
导出常量上传驱动=(道具)=>{
const[image,setImage]=useState(null);
常量[uploadPercent,setUploadPercent]=useState(0)
const[mimeType,setMimeType]=useState(“”)
useffect(()=>{
(异步()=>{
如果(Platform.OS!=“web”){
const{status}=等待ImagePicker.requestCameraRollPermissionsAsync();
如果(状态!=“已授予”){
警报('抱歉,我们需要摄像头滚动权限才能执行此操作!');
}
}
})();
}, []);
const pickImage=async()=>{
常量baseURL=https://dummy-server-address/api';
//在拾取媒体时同时获取访问令牌
const[{response},result]=wait Promise.all([
取回(
`${baseURL}/services/fetch访问令牌`,
{
模式:“cors”,
}
)
.然后((res)=>res.json())
.然后((resp)=>resp)
.catch((err)=>console.log(err)),
ImagePicker.launchImageLibraryAsync({
mediaTypes:ImagePicker.MediaTypeOptions.All,
允许编辑:对,
相位:[4,3],
质量:1,,
})
]).catch((err)=>console.log(err))
//确保所有需要的参数/字段都存在
如果(!result.cancelled&&response.token){
const accessToken=response.token
const uri=“file://”+result.uri.split(“file:/”).join(“”);
setImage(uri);
常量文件=结果
让filename=uri.split('/').pop();
让match=/\.(\w+)$/.exec(文件名);
让type=match?`image/${match[1]}`:`image`;
file.name=文件名;
file.type=type
file.uri=uri
console.log(文件)
setMimeType(file.type)
//使用fetch和FormData API上载图像
设formData=new formData();
常量元数据={
name:file.name,
类型:file.type | |“多部分/表单数据”,
家长:[“1yz6MUU0YfXz0rl7TObq-JOPCmC6sHKdQ”],
};
//为上传构建文件元数据
formData.append(
“元数据”,
新Blob([JSON.stringify(metadata)],{type:“application/JSON”})
);
//append('file',{uri,名称:filename,type});
formData.append('file',file);
常量url=
"https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id";
//让上传百分比;
const upload_res=等待axios(url{
方法:“张贴”,
标题:{
授权:“持票人”+accessToken,
},
数据:formData,
onUploadProgress:(p)=>{
setUploadPercent((p.loaded/p.total)*100)
},
})
.catch(err=>console.log({err}))
.最后(()=>setUploadPercent(0));
log({data:upload_res.data});
}否则{
抛出新错误('您没有进行上载的所有正确变量')
}
};
返回(
{!!uploadPercent&&uploadPercent:{${uploadPercent.toFixed(2)}%`}
{image&&mimeType.includes('image')&&}
)
}
const styles=StyleSheet.create({
按钮:{
位置:'绝对',
前几名:“10%”
},
上载百分比:{
颜色:“西红柿”,
尺寸:15,
fontWeight:'粗体',
marginBottom:20
}
})
请问,我可能做错了什么?- 如果将服务帐户文件保存到非他的驱动器,则需要将参数
设置为supportsAllDrives
true
- 或者,使用以使服务帐户代表您上载文件-在这种情况下,您不需要与服务帐户共享文件夹
- 记住,a不是你。服务帐户有自己的Google drive帐户。如果你做一个测试,你会看到文件。它们正在上载到服务帐户驱动器帐户
如果你想将它们上传到你自己的google drive帐户,那么你可以使用服务帐户的电子邮件地址,在你的个人硬盘帐户上共享一个文件夹,并授予它上传到该文件夹的权限。请记住让服务帐户将您的个人帐户授予文件,否则您将无法访问这些文件,因为服务帐户在上载文件时将是其所有者
如果您有gsuite帐户,则可以设置upl并允许服务帐户模拟域上的用户,并代表该用户上载这些用户,这意味着权限将不再存在问题
元数据名称问题
你的元数据应该包括你正在上传的文件名,如果你不这样做,那么它将以“无标题”作为其名称上传。您应该传递元数据变量,这似乎传递了元数据字符串
formData.append(
"metadata",
new Blob([JSON.stringify(metadata)], { type: "application/json" })
);
如何进行身份验证?如果驱动器已成功上载,但不在您的驱动器上-最明显的是,您正在使用一个服务客户端将文件上载到其自己的驱动器。感谢@ziganotschka的回复。我在Cl上认证