Google Drive Picker API报错‘this.Qi is not a function’的解决咨询
Google Drive Picker API:
PickerBuilder抛出this.Qi is not a function错误的解决方法 问题场景
项目中集成Google Drive Picker API,代码参考官方示例实现,但调用PickerBuilder()时触发this.Qi is not a function错误,核心代码如下:
gapiLoaded() { window['gapi'].load('client:picker', this.intializePicker); } async intializePicker() { await window['gapi'].client.load('https://www.googleapis.com/discovery/v1/apis/drive/v3/rest'); } gisLoaded() { this.tokenClient = window['google'].accounts.oauth2.initTokenClient({ client_id: MY_Client_Id, scope: 'https://www.googleapis.com/auth/drive.readonly', callback: '', // defined later }); this.gisInited = true; } handleAuthClick() { this.tokenClient.callback = async (response) => { if (response.error !== undefined) { throw (response); } this.accessToken = response.access_token; this.createPicker(); }; if (this.accessToken === null) { this.tokenClient.requestAccessToken({prompt: 'consent'}); } else { this.tokenClient.requestAccessToken({prompt: ''}); } } createPicker() { var view = window['google'].picker.View(window['google'].picker.ViewId.DOCS); var picker = window['google'].picker.PickerBuilder() .enableFeature(window['google'].picker.Feature.NAV_HIDDEN) .enableFeature(window['google'].picker.Feature.MULTISELECT_ENABLED) .setDeveloperKey('MY_APP_KEY') .setAppId('MY_PROJECT_ID') .setOAuthToken(this.accessToken) .addView(view) .addView( window['google'].picker.DocsUploadView()) .setCallback(this.pickerCallback) .build(); picker.setVisible(true); } async pickerCallback(data) { if (data.action === window['google'].picker.Action.PICKED) { let text = `Picker response: \n${JSON.stringify(data, null, 2)}\n`; const document = data[window['google'].picker.Response.DOCUMENTS][0]; const fileId = document[window['google'].picker.Document.ID]; console.log(fileId); const res = await window['gapi'].client.drive.files.get({ 'fileId': fileId, 'fields': '*', }); text += `Drive API response for first document: \n${JSON.stringify(res.result, null, 2)}\n`; console.log(text) } }
解决方案
1. 确保Picker模块完全加载后初始化
gapi.load('client:picker')可能存在模块加载不彻底的情况,需等待window.google.picker就绪后再执行初始化:
gapiLoaded() { window['gapi'].load('client:picker', async () => { // 等待Picker脚本挂载到window const checkPickerReady = () => { if (window['google']?.picker) { this.intializePicker(); } else { setTimeout(checkPickerReady, 300); } }; checkPickerReady(); }); }
2. 修复回调函数的上下文绑定
setCallback(this.pickerCallback)会导致回调执行时上下文丢失,引发内部方法调用错误,需绑定正确的上下文:
// 方式一:箭头函数包裹 .setCallback(data => this.pickerCallback(data)) // 方式二:bind绑定上下文 .setCallback(this.pickerCallback.bind(this))
3. 验证API凭据的有效性
- 确认Google Cloud控制台中已启用Drive Picker API
- 检查
setDeveloperKey的API密钥是否配置了正确的域名限制(若开启了限制) - 确保
setAppId的项目ID与OAuth客户端ID所属项目一致 - 验证OAuth客户端ID的授权范围包含
https://www.googleapis.com/auth/drive.readonly
4. 同步GAPI与GIS的初始化状态
需确保GAPI和Google Identity Services(GIS)都初始化完成后再触发授权:
// 新增状态标记 gisInited = false; gapiInited = false; gapiLoaded() { window['gapi'].load('client:picker', async () => { await window['gapi'].client.load('https://www.googleapis.com/discovery/v1/apis/drive/v3/rest'); this.gapiInited = true; }); } gisLoaded() { this.tokenClient = window['google'].accounts.oauth2.initTokenClient({ client_id: MY_Client_Id, scope: 'https://www.googleapis.com/auth/drive.readonly', callback: '', }); this.gisInited = true; } handleAuthClick() { if (!this.gisInited || !this.gapiInited) { console.warn('API初始化未完成,请稍后再试'); return; } // 原授权逻辑... }
5. 切换为直接引入Picker脚本
若通过gapi.load加载不稳定,可直接在HTML中引入所需脚本,确保加载顺序正确:
<!-- 加载GAPI核心 --> <script src="https://apis.google.com/js/api.js"></script> <!-- 加载GIS客户端 --> <script src="https://accounts.google.com/gsi/client"></script> <!-- 加载Picker脚本 --> <script src="https://apis.google.com/js/picker.js"></script>
内容的提问来源于stack exchange,提问作者Sriram Sundar
相关产品推荐
相关产品推荐

