VueJS中如何正确获取Google Drive返回的文件对象与base64数据
问题描述
我需要在VueJS项目中选取Google Drive上的文件并转换为标准File对象,项目中已引入vue-google-picker组件,该组件默认仅返回文件URL,因此我编写了如下转换代码:
async convertToFile(docs) { return new Promise( resolve => { docs.map(doc => { if (doc.url) { gapi.load('client', function () { gapi.client.load('drive', 'v3', function () { var file = gapi.client.drive.files.get({ 'fileId': doc.id, 'alt': 'media' }); console.log(file) file.execute(function (resp) { console.log(resp) resolve(resp) }); }); }); } }); } ) }
运行代码时,console.log(file)可正常输出gapi请求对象,如下图所示:
但回调中console.log(resp)的输出为false,查看浏览器网络面板的preview标签,可看到接口实际已返回文件对应的base64格式数据。需要解决两个问题:
- 如何在代码中正确获取到该base64数据?
- 有没有其他可从Google Drive获取文件对象的可行替代方案?
问题原因
调用gapi.client.drive.files.get并传入alt: 'media'参数下载文件内容时,旧版execute回调仅支持解析JSON格式响应,当响应内容是二进制/Base64等非JSON格式时,execute方法不会透传实际响应体,直接返回false。
解决方案
方案1:修正现有gapi调用逻辑
弃用execute回调,直接使用gapi请求原生返回的Promise,同时配置responseType指定响应格式,拿到Blob数据后可直接转标准File对象,也可进一步转Base64。
修正后的完整代码:
async convertToFile(docs) { // 全局只加载一次gapi依赖,避免重复加载 if (!gapi.client.drive) { await new Promise(resolve => gapi.load('client', resolve)) await new Promise(resolve => gapi.client.load('drive', 'v3', resolve)) } const fileList = [] for (const doc of docs) { if (!doc.id) continue // 发起请求,指定响应类型为blob const response = await gapi.client.drive.files.get({ fileId: doc.id, alt: 'media' }, { responseType: 'blob' }) // 从响应头提取真实文件名、MIME类型 const disposition = response.headers['Content-Disposition'] || response.headers['content-disposition'] let fileName = doc.name const nameMatch = disposition?.match(/filename="?([^"]+)"?/) if (nameMatch?.[1]) fileName = nameMatch[1] const mimeType = response.headers['Content-Type'] || response.headers['content-type'] || doc.mimeType // 构造标准File对象 const standardFile = new File([response.body], fileName, { type: mimeType }) fileList.push(standardFile) } return fileList }
如果需要获取Base64格式数据,可加一层Blob转Base64的工具方法:
blobToBase64(blob) { return new Promise((resolve, reject) => { const reader = new FileReader() reader.onloadend = () => resolve(reader.result) reader.onerror = reject reader.readAsDataURL(blob) }) }
方案2:直接构造fetch请求拉取文件
不依赖gapi的drive接口封装,直接带OAuth令牌调用下载接口,逻辑更灵活可控:
- 从Picker返回的文件信息中拿到文件ID
- 拼接下载接口地址:
https://www.googleapis.com/drive/v3/files/${fileId}?alt=media - 把当前用户的有效OAuth access token放到请求头
Authorization: Bearer ${accessToken}中发起请求 - 拿到响应Blob后直接构造标准File对象
示例代码:
async convertToFile(docs, accessToken) { const fileList = [] for (const doc of docs) { if (!doc.id) continue const res = await fetch(`https://www.googleapis.com/drive/v3/files/${doc.id}?alt=media`, { headers: { 'Authorization': `Bearer ${accessToken}` } }) const blob = await res.blob() const standardFile = new File([blob], doc.name, { type: doc.mimeType }) fileList.push(standardFile) } return fileList }
注意事项
- 提前确认Google API密钥、OAuth scope配置了
https://www.googleapis.com/auth/drive.readonly或对应文件的读取权限,否则会返回403权限错误 - 不要在文件遍历循环里重复加载gapi依赖,会造成不必要的性能消耗,依赖加载一次即可全局复用
- 如果选取的是Google Docs/Sheets/Slides这类云端原生编辑文件,不能直接用
alt=media拉取原文件,需要指定导出格式,比如导出为docx/xlsx/pptx,请求时额外传入对应mimeType参数即可
内容的提问来源于stack exchange,提问作者Maha Waqar
相关产品推荐
相关产品推荐

