Firebase Can';找不到使用RESTAPI上传到Google Drive的文件

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',

我正在尝试使用RESTAPI和服务帐户将媒体文件上载到Google Drive。我有一个云函数后端,在那里我使用GoogleDrive API的正确作用域进行身份验证,并将访问令牌(如下面的代码段所示)返回给客户端,然后客户端可以向GoogleDrive发出上载请求

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上认证